Code Monkey home page Code Monkey logo

sanity-image's Introduction

sanity-image

Latest version Dependency status Open issues React version compatibility

A well-considered React component for displaying images from Sanity. At a glance:

  • Outputs a single <img> tag, no nested DOM structure to mess with
  • Zero styling included so you can style it however you want…it's just an img tag!
  • Supports low-quality image previews out of the box, without build-time penalties (native lazy loading)
  • Generates a srcSet automatically based on the width you specify
  • Dynamic srcSet factor based on image output width
  • Knows exactly what size the image will be and sets width and height attributes accordingly
  • Supports crop and hotspot values from the Sanity Studio
  • Automatically crops to the most “interesting” part of the image if the aspect ratio changes and no hotspot is provided
  • Images are never scaled up
  • Tiny 4kb bundle size (2kb gzipped)
  • No dependencies
  • TypeScript support
  • Works with Gatsby, Next.js, and any other React-based framework
  • Polymorphic component (supports as prop to render as a custom component)

Quick Start

Install it:

yarn add sanity-image
# or
npm install sanity-image

Use it:

You can find the full writeup on getting going below, but in the interest of making it easy to see if this is the thing you are looking for, here’s a quick example of most of what you’ll need to know:

Simplest Case:

This will render the image out assuming it will be displayed at half its original width with a srcSet included (multiplies vary based on original image size):

import { SanityImage } from "sanity-image"

const YourSweetComponent = ({ image }: ComponentProps) => (
  <SanityImage
    // Pass the Sanity Image ID (`_id`) (e.g., `image-abcde12345-1200x800-jpg`)
    id={image._id}
    baseUrl="https://cdn.sanity.io/images/abcd1234/production/"
    alt="Demo image"
  />
)

More full-featured example:

import { SanityImage } from "sanity-image"

const YourSweetComponent = ({ image }: ComponentProps) => (
  <SanityImage
    // Pass the Sanity Image ID (`_id`) (e.g., `image-abcde12345-1200x800-jpg`)
    id={image._id}
    //
    // You can set the base URL manually, or let it be constructed by passing
    // `projectId` and `dataset` props.
    baseUrl="https://cdn.sanity.io/images/abcd1234/production/"
    //
    // Specify how big it is expected to render so a reasonable srcSet can be
    // generated using `width`, `height`, or both
    width={500}
    height={250}
    //
    // Choose whether you want it to act like `object-fit: cover` or
    // `object-fit: contain`, or leave it out to use the default (contain)
    mode="cover"
    //
    // Have hotspot or crop data from Sanity? Pass it in!
    hotspot={image.hotspot}
    crop={image.crop}
    //
    // Want low-quality image previews? Fetch them from Sanity and pass them in too.
    preview={image.asset.metadata.lqip}
    //
    // Have a burning desire to have Sanity change the format or something?
    // Most of the visual effects from the Sanity Image API are available:
    queryParams={{ sharpen: 30, q: 80 }}
    //
    // Anything else you want to pass through to the img tag? Go for it!
    alt="Sweet Christmas!"
    className="big-ol-image"
    sizes="(min-width: 500px) 500px, 100vw"
  />
)

export default YourSweetComponent

That’s the gist. Read on for more. 👇

Details

How it works at a glance:

  • The image ID is parsed to determine the source image dimensions and format
  • SVG images get special treatment from the Sanity Image API (they don't support params), so they're handled a bit differently (check SanityImage.ts for details)
  • All other images have src and srcSet props generated based on the width and height props you pass in (or the image dimensions if you don't pass in a width or height)
  • The srcSet widths depend on the size of the output image and the original image; there's some logic to avoid wasteful tiny images or giant jumps in size between large entries (see dynamicMultipliers in urlBuilder.ts)
  • Values in the srcSet are never duplicated and never upscale the image
  • Since we can compute the output dimensions of the image in all cases, the width and height attributes are set automatically to avoid layout shifts
  • A few image params are applied by default:
    • auto=format - Sanity will use WebP images if they're supported by the browser (note: if you specify fm manually, this won't be set)
    • fit - if the image aspect ratio isn't changed, this will be set to max; if the aspect ratio will change it's set to crop; you don't really need to worry about this though
    • q - the quality is set to 75 by default, but you can override it with the queryParams prop
  • The loading attribute will be set to lazy if it isn't supplied; use loading="eager" for images above the fold
  • The alt attribute will be set to an empty string if it isn't supplied; set it if it isn't a decorative image!
  • By default it renders an img tag (two if you pass in a preview), but you can pass in a custom component to render as using the as prop (see the SanityImage.test.tsx file for an example of this)
  • If you wanna get weird you can also import the buildSrc and buildSrcSet exports to do your own thing with. You get a lot of the magic still this way with a skosh more control.
  • Similarly, the parseImageId function is available as a named export; it takes an image ID and returns an object with the image id, dimensions, and format.
  • Query params passed to Sanity are all sorted and minimized like heck for improved caching and smaller URLs. Pass in a height only? Don't be alarmed, but it'll be converted to a w param without altering what you're asking Sanity for. Ask for mode="cover" but the aspect ratio matches the source? It'll be ignored and fall back to fit=max with just a w param. You get the idea (I hope, or at least, I'm pretending, but no judgement if you don't, it's definitely 11:09pm and I'm on fumes)

Props

This is mostly copied and reformatted from the types.ts file; if you're comfortable with TypeScript, that might give you more detail.

  • id (string) — Required - The Sanity Image ID (_id or _ref field value)
  • mode ("cover" | "contain") — Optional - Use cover to crop the image to match the requested aspect ratio (based on width and height). Use contain to fit the image to the boundaries provided without altering the aspect ratio. Defaults to "contain".
  • width (number) — Optional - The target width of the image in pixels. Only used for determining the dimensions of the generated assets, not for layout. Use CSS to specify how the browser should render the image instead.
  • height (number) — Optional - The target height of the image in pixels. Only used for determining the dimensions of the generated assets, not for layout. Use CSS to specify how the browser should render the image instead.
  • hotspot ({ x: number, y: number }) — Optional - The hotspot coordinates to use for the image. Note: hotspot width and height are not used.
  • crop ({ top: number, bottom: number, left: number, right: number }) — Optional - The crop coordinates to use for the image.
  • preview (string) — Optional - A low-quality image preview to use while the full-size image is loading. This should be a base64-encoded image string.
  • as (React.ElementType) — Optional - The component to render as. Defaults to "img".
  • baseUrl (string) — Optional - The base URL to use for the image. If not specified, the projectId and dataset props will be used to construct the URL.
  • projectId (string) — Optional - The Sanity project ID to use for the image. Only used if baseUrl is not specified.
  • dataset (string) — Optional - The Sanity dataset to use for the image. Only used if baseUrl is not specified.
  • queryParams (object) — Optional - An object of query parameters to pass to the Sanity Image API. See the Sanity Image API documentation for a list of available options.

That's the gist. There's a ton more in the inline comments and types and such, and I'll add more details as I think of them. Feel free to open an issue or start a discussion if you have questions or suggestions, or find me on the Sanity Slack!

⚠️ Minor gotchas with deferred loading

SanityImage is relying on browser-native deferred image loading. This generally works fine in browsers that support it, but there are situations where the unloaded image is hidden or covered, resulting in the full image never loading.

If this happens, you can override the styles set on the full-size image using the img[data-loading] selector. This image sits immediately adjacent to the spaceball image and has the following default styles while loading:

position: absolute;
width: 10px !important; /* must be > 4px to be lazy loaded */
height: 10px !important; /* must be > 4px to be lazy loaded */
opacity: 0;
zindex: -10;
pointerevents: none;
userselect: none;

Tips

Wrap it internally

I recommend creating a wrapper component internally to pass your baseUrl prop and pass through any props. This keeps the configuration in one place and gives you an entry point to add any other logic you might need. Here's a TypeScript example (for JavaScript, just remove the type annotation after props):

import { SanityImage } from "sanity-image"

const projectId = process.env.SANITY_PROJECT_ID
const dataset = process.env.SANITY_DATASET
const baseUrl = `https://cdn.sanity.io/images/${projectId}/${dataset}/`

export const Image = (
  props: Omit<
    React.ComponentProps<typeof SanityImage>,
    "baseUrl" | "dataset" | "projectId"
  >
) => <SanityImage baseUrl={baseUrl} {...props} />

Styling your images

I recommend setting something like the following CSS for images in your project, then overriding styles as needed. This will ensure images act like block-level elements with infinitely scalable contents even with the width and height attributes set. It also makes it easier to handle responsiveness—if your container gets smaller, the image gets smaller.

img {
  display: block;
  max-width: 100%;
  width: 100%;
  height: auto;
}

Here's an example of how that works when using, for example, a 3-column grid that fills the viewport until it is a maximum of 1,200px wide (plus padding). This produces columns that are 390px at most on desktop:

<div
  css={{
    display: "grid",
    gridTemplateColumns: "repeat(3, 1fr)",
    gap: 15,
    maxWidth: 1240,
    paddingInline: 20,
    marginInline: "auto",
  }}
>
  {["image-a", "image-b", "image-c"].map((imageId) => (
    <div key={imageId}>
      <SanityImage
        id={imageId}
        baseUrl="..."
        width={390}
        sizes="(min-width: 1240px) 390px, calc((100vw - 40px - 30px) / 3)"
      />
    </div>
  ))}
</div>

If you need these images to all match in height, it's a good idea to switch to cover mode. With the height set to 260px and mode="cover", this will produce images with a 3:2 aspect ratio that fill the column width even if the source image is too small:

<SanityImage
  id={imageId}
  baseUrl="..."
  width={390}
  height={260}
  mode="cover"
  sizes="(min-width: 1240px) 390px, calc((100vw - 40px - 30px) / 3)"
/>

In this example we don't pass a hotspot value, so the image will be cropped based on what Sanity thinks is the most interesting part of the image since SanityImage automatically sets crop=entropy in these cases. If you want to override that, you can pass a hotspot value.

Background images

Using SanityImage for background images is easy, you just style the image to match the expectations of your mockup. In most cases that means setting position: relative on the container you want to fill, then using absolute positioning for the image. Here’s an example:

<section
  css={{
    position: "relative",
    paddingBlock: 100,
  }}
>
  <SanityImage
    id="..."
    baseUrl="..."
    width={1440}
    css={{
      position: "absolute",
      top: 0,
      left: 0,
      width: "100%",
      height: "100%",
      objectFit: "cover",
      userSelect: "none",
      zIndex: 1,
    }}
    alt=""
  />

  <div css={{ position: "relative", zIndex: 2 }}>
    <h1>Your big hero copy</h1>
    <LinkButton to="/signup/">Get started</LinkButton>
  </div>
</section>

This will cause the section to be sized based on the content inside of the div, and the image will be sized to fill the entire section. The aspect ratio of the image will be maintained due to the use of object-fit: cover. Note that we are still using mode="contain" for SanityImage here. If you have a rough idea of the height your section, you can set height and mode="cover" which will prevent, for example, a portrait orientation image from being retrieved and cropped by the browser.

Since the z-index is set higher on the div containing the content, it will show above the image. This example also sets user-select: none on the image to prevent the image from being selected when the user clicks and drags on the page to make it behave more like a traditional background image.

Fetching data from Sanity via GROQ

If you're using Sanity's GROQ query language to fetch data, here is how I recommend fetching the fields you need from a typical image with the hotspot, crop, and low-quality image preview included:

"id": asset._ref,
"preview": asset->metadata.lqip,
hotspot { x, y },
crop {
  bottom,
  left,
  right,
  top,
}

License

Copyright ©2023 Corey Ward. Available under the MIT License.

sanity-image's People

Contributors

coreyward avatar corygibbons avatar dependabot[bot] avatar jeffbeltran avatar mrspecific avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

sanity-image's Issues

Pure function evaluates `useState` for no reason, when using `buildSrc`

Importing sanity-image in any shape, in my files will, of course, load the whole exported module. Some of the parts fo the exported module use client component hooks like useState, I am making a wild guess that it is the blur+load logic.

In any case, this makes the whole package unusable in server components, something that React (and NextJS) are heavily leaning into. Now, let's look at it in two use cases:

  1. Somehow, magically making the package work as part of server components would be great, as the html output would contain a fully baked img tag. This will, however screw up the loading (i assume)? So it's a no-go.
  2. Since the above is not feasible, it would be amazing to extract some of the functional parts into a sub module, for example buildSrc function can easily live in its own file, as it doesn't require react hooks to work.

Any thoughts?

How to use

Sir, I saw you on the YouTube video, where you explained how it will work. I want to know how can I use it in my sanity studio.

Thank You
Param

When using preview, main image won't ever show unless it overlaps the visible area (usually the preview image)

Hi @coreyward, first of all thanks a lot for this awesome library that finally allowed us to start using hotspot/crop easily!

I've stumbled upon an issue which feels like it's a problem in the library, but maybe I'm using it wrong.

When we use a preview, we get two img tags, but unless we use the right styles (e.g. using display: flex) in the wrapper div, the second img tag (the main image) is rendered besides or below the preview img, like this:
2023-09-01_19-48

This in turn means it may get rendered in a place that is not visible and the browser never initiates the loading of the image, meaning the preview never gets replaced.

There's a bunch of ways to fix this with CSS from outside the library, but it would be nice if we could avoid this altogether directly in the library, though I'm not sure how without introducing a wrapper div around the two images (so we can ensure they stay on top of each other), and having a wrapper div probably goes against the idea of this library being just an img tag.

For now I introduced this hack which seems to work everywhere I need it too, but it's definitely not library-quality code:

.image[data-loading='true'] {
  // HACK: Usually ensures that independently of the position of the
  // main image during loading compared to the preview image
  // (usually it's on top, to the right, or to the left),
  // the main image overlaps with the preview image and thus is considered visible.
  transform: translate(-10%, -10%);
}

Layout Shift when using preview prop

Noticed that when I pass in a preview image as outlined in examples I'm getting layout shift when the image is loading. Can cause images below the fold to overflow the page.

Preview LQIP randomly not going away and doesn't show full image?

"I'm trying to solve a problem where the Low-Quality Image Placeholder (LQIP) sometimes doesn't display the full image upon loading or when it's in the viewport. How can I fix this?

"use client"

import { SanityImage } from "sanity-image"

import { dataset, projectId } from "@/sanity/lib/api"

interface ImageBoxProps {
  image?: Image
  mode?: "cover" | "contain"
  loading?: "lazy" | "eager"
  width?: number
  height?: number
  size?: string
  classesWrapper?: string
  preview?: boolean
}

const ImageBox = ({
  image,
  width = 1400,
  height,
  classesWrapper,
  mode,
  loading = "lazy",
  preview = true // Set the default value of preview to true (enabled)
}: ImageBoxProps) => {
  if (!image?._id) return null

  const { _id, lqip, hotspot, crop, alt } = image

  const previewValue = preview ? lqip : undefined

  return (
    <SanityImage
      id={_id}
      className={classesWrapper}
      dataset={dataset}
      projectId={projectId}
      hotspot={hotspot}
      preview={previewValue}
      crop={crop}
      width={width}
      height={height}
      mode={mode}
      alt={alt}
      loading={loading}
      queryParams={{ q: 90 }}
    />
  )
}

export default ImageBox

Getting started and usage of Sanity Image

Hi!

I'm a total newbie who has arrived late for the dev party, so I ask a lot of dumb questions.
The "dumb" request now is that it would help us newbies with no experience to get started with this component if you explained in the README where your code is going, and what you need to get it up and running in the studio.
A bit like is explained with the Media browser plugin: https://github.com/sanity-io/sanity-plugin-media#usage
Here it says where the code goes, etc.

I know 99% probably understand how to get this going, but I, for one, is just understanding that this is a great component, but cant' get started ...

Adding style to <SanityImage /> causes breaks lqip preview position

Great stuff as always

I'm using style on the image to make hotspot work correctly when using object fit like this:

 <SanityImage
      id={_ref}
      projectId={env.NEXT_PUBLIC_SANITY_PROJECT_ID}
      dataset={env.NEXT_PUBLIC_SANITY_DATASET}
      width={width ?? undefined}
      height={height ?? undefined}
      mode="cover"
      hotspot={hotspot ?? undefined}
      crop={crop ?? undefined}
      preview={lqip}
      alt={alt ?? ""}
      sizes={sizes}
      style={{
        objectPosition: hotspot
          ? `${hotspot?.x * 100}% ${hotspot?.y * 100}%`
          : "center",
      }}
      loading={eager ? "eager" : "lazy"}
      className={cn(className)}
    />

I think due to the spread of props in the ImageWithPreview file using the style like this overwrites the styles while the image is loading.

How to preload image to improve LCP score?

Utilizing SanityImage to serve up a hero with a background image above-the-fold Lighthouse indicates to improve my LCP time to:

Preload the image used by the LCP element in order to improve your LCP time.

and links to my image and docs. In SanityImage is there a way to preload the image or implement the approach in a useEffect like:

import { useEffect, useState } from 'react';

export const useImageLoader = (initialSrc: string, currentSrc: string) => {
  const [imageSrc, _setImageSrc] = useState(initialSrc);

  useEffect(() => {
    const img = new Image();
    img.onload = () => {
      _setImageSrc(currentSrc);
    };
    img.src = currentSrc;
  }, [currentSrc]);

  return [imageSrc];
};

what is the best solution to resolve this issue?

`lqip` isn't being cropped by Sanity

Previous Issues that seem related but don't really look into the lqip aspect ratio:

I was getting significant layout shift on some pages. When I disabled JS I discovered that image aspect ratios were all wrong.

First I thought that width and height attributes are missing on previews, but then I realised that they aren't missing, and also that makes no difference, because the LQIP isn't the same size as the actual image.

  • LQIP comes from Sanity, before the image URL is constructed by sanity-image, and thus it represents the full size image (unless image is cropped in Sanity).
  • On the other hand, our URL gets constructed by sanity-image which adds ?auto=format&crop=entropy&fit=crop&h=350&q=85&w=350 to it.

So, we end up in a situation where LQIP doesn't really represent what the image will actually look like.
In my concrete example:

Screenshot 2023-07-08 at 10 31 45

--

Now, this isn't really a sanity-image bug. We gave it data, and it did exactly what we expected it to.

But I'm wondering if there is something we could do with the CSS surrounding the preview image, to basically center crop it.
Or if there is a way for us to get an updated cropped LQIP possibly by fetching &w=20&h=20

RSC: Previews should execute only on the client

We had a nice and fruitful discussion on an unrelated issue - here

@coreyward explored possible ways of achieving the move over to deprecating client-only APIs like react hooks, which would allow the library to support non-browser environments, like React Server Components. None of the solutions are ideal, and this feature is definitely not optional.

I would like to explore a different viewpoint - it might just be okay, as it is...

From my limited testing, I've observed that the library is perfectly capable of generating the appropriate img object on the server. The HTML that server produces will contain both images:

<!-- BLUR -->
<img 
    data-lqip="true" 
    height="301" 
    width="400" 
    src="data:image/png;base64,iVABJRU5ErkJggg==">

<!-- Actual image -->
<img 
    data-loading="true" 
    style="height:10px !important;opacity:0;pointer-events:none;position:absolute;user-select:none;width:10px !important;z-index:-10" 
    loading="lazy" 
    fetchpriority="auto" 
    srcset="
        https://cdn.sanity.io/images/aw8r55m1/production/a19511b800756e78d2d7001713326399fd368456-1232x928.png?auto=format&amp;fit=max&amp;q=85&amp;rect=0,0,1232,928&amp;w=200 200w, 
        https://cdn.sanity.io/images/aw8r55m1/production/a19511b800756e78d2d7001713326399fd368456-1232x928.png?auto=format&amp;fit=max&amp;q=85&amp;rect=0,0,1232,928&amp;w=400 400w, 
        https://cdn.sanity.io/images/aw8r55m1/production/a19511b800756e78d2d7001713326399fd368456-1232x928.png?auto=format&amp;fit=max&amp;q=85&amp;rect=0,0,1232,928&amp;w=600 600w, 
        https://cdn.sanity.io/images/aw8r55m1/production/a19511b800756e78d2d7001713326399fd368456-1232x928.png?auto=format&amp;fit=max&amp;q=85&amp;rect=0,0,1232,928&amp;w=800 800w" 
    src="https://cdn.sanity.io/images/aw8r55m1/production/a19511b800756e78d2d7001713326399fd368456-1232x928.png?auto=format&amp;fit=max&amp;q=85&amp;rect=0,0,1232,928&amp;w=400" 
    width="400" 
    height="301">

The client will hydrate the page, and react when image is loaded.

This is in fact literally what the library is intended to do. The functionality that the library provides is inherently a client-side functionality. I think there is A LOT of misunderstanding going around about what roles client and server traditionally have, in the React world right now, and many people are looking to forcibly make everything into a server component for no reason at all. I've literally seen people asking how to do server-side page transitions and canvas elements, and similar is happening here, when we ask about replacing what is fundamentally a client-side functionality, with a server side one.

--

Now, what I might suggest instead is for us to allow the library users to use the component without the preview. Without looking at the code (yet) i can imagine that you have a function which you call to get the actual image tag we've seen above, wrapped with a bunch of preview logic - so, why not expose it?

If we exposed such a (theorethical) component or function (similarly how we expose buildSrc for direct usage) the use who really wishes to just get a static img tag - would get it. Without ever impacting normal usage, changing any APIs, or giving your library a maintenance overhead.

Will other frameworks be supported?

I have a nuxt project that is in dire need of this component. Will there be a framework independent version of this developed in the future or a nuxt version?

Animation on native lazy load – onLoadingComplete or [data-loading] attribute to help determine when images are loaded?

Hey Corey,

I suspect you’ve made a decision not to accommodate this – but I am personally very fond of having the option to fade images in once loaded. With next/image this can be done with onLoadingComplete, as onLoad isn’t triggered for cached images. With lazysizes this was always easy because convenient classes were appended at different states.

You mention a [data-loading] attribute in the docs but I can’t see this being applied or removed for unloaded img elements.

I’ve also seen examples where a ref is used, but obviously I cannot pass a ref to the sanity-image component.

Sorry that this is more of a question – would be very grateful for any pointers in the right direction.

Many thanks,

Simon

Question: SWC module transpilation required for nullish coalescing operator

Hey Corey – thanks so much for your work on this package.

It took me a little while to debug this but if you’re targeting Safari 12/13 like Next itself is designed to cover, then adding module transpilation is necessary e.g. transpilePackages: ['sanity-image'] inside your next.config. This is because the nullish coalescing operator is not supported by these browsers and SWC doesn’t transpile packages by default.

I was wondering what you think about this – should the docs have a "gotchas" section which explains this?

Wrap it internally example does not give accurate prop types

import { SanityImage } from "sanity-image"

const projectId = process.env.SANITY_PROJECT_ID
const dataset = process.env.SANITY_DATASET
const baseUrl = `https://cdn.sanity.io/images/${projectId}/${dataset}/`

export const Image = (
  props: Omit<
    React.ComponentProps<typeof SanityImage>,
    "baseUrl" | "dataset" | "projectId"
  >
) => <SanityImage baseUrl={baseUrl} {...props} />

Getting the following type error.

Property 'id' is missing in type '{ baseUrl: string; }' but required in type 'ImageQueryInputs'.

If I remove the Omit it gets rid of the error but then I'm noticing things like className don't autocomplete.

Passing down data attributes?

Is it possible to pass a prop for one or more data attributes to the img element? Apologies if I missed that in the README.

Preview image and loaded image have different aspect ratio

I'm noticing a small layout shift when the image finishes loading and the preview image is swapped out with the real image.

The real image is 1128x600px (an aspect ratio of 1.88), but the preview image has an size of 20x10px (an aspect ratio of 2). When the preview image is shown, Chrome uses the aspect ratio from the preview image's intrinsic size and ignores the width/height attributes.

I'm hacking around this on my end by doing this:

style={{ "--inherent-aspect-ratio": `${image.width} / ${image.height}` }}
:where(.image[data-lqip="true"]) {
  aspect-ratio: var(--inherent-aspect-ratio);
}

This is made a bit more cumbersome by the fact that ImageWithPreview.tsx overrides the style object that hides the loading style when I send in a style prop so I had to duplicate the styles that hide the loading image as well.

I think the preview image should set an aspect-ratio prop based on the given width/height and not assume the preview image has the same aspect ratio.

Question: lazy loading with translateX images

Hey Corey,

Do you have any plans to support this? I think it would be a really useful feature but I’ll make a hacky solution if not.

It accounts for a variety of possibilities likely to occur in modern web applications like scroll transitions and many popular slideshow frameworks e.g. Swiper. It was handled very elegantly by the old lazysizes package.

I’d really appreciate your thoughts.

Thanks again,

Simon

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.