diff --git a/pages/collective.tsx b/pages/collective.tsx index 0b7c8346..f90d4e35 100644 --- a/pages/collective.tsx +++ b/pages/collective.tsx @@ -67,9 +67,6 @@ const Page: NextPage = props => { srcSet={srcSet} style={{ marginBottom: 'var(--size-l)', - }} - imgStyle={{ - width: '100%', borderRadius: 'var(--radius)', }} /> diff --git a/src/components/Card/index.tsx b/src/components/Card/index.tsx index 2f0510f8..2bff9b22 100644 --- a/src/components/Card/index.tsx +++ b/src/components/Card/index.tsx @@ -1,6 +1,7 @@ import './styles.css' import cx from 'classnames' import Link from 'next/link' +import { Image } from '../Image' export type CardLayout = 'simple' | 'featured' export type CardProps = { @@ -19,8 +20,7 @@ export const Card: React.FC = props => (
- {props.img.alt} = memo(props => { + const [imageSrc, setImageSrc] = useState<[string, string]>([null, null]) + const ref = useRef() + const onLoad = useCallback((event) => { + event.target.classList.add('loaded') + event.target.classList.remove('pending') + }, []) + + useEffect(() => { + if (ref.current) { + ref.current.classList.add('pending') + } + }) + + useEffect(() => { + let observer: IntersectionObserver + let didCancel = false + + if (ref.current && imageSrc[0] !== props.src) { + if (IntersectionObserver) { + observer = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if ( + !didCancel && + (entry.intersectionRatio > 0 || entry.isIntersecting) + ) { + setImageSrc([props.src, props.srcSet]) + observer.unobserve(ref.current) + } + }) + }, + { + threshold: 0.01, + rootMargin: "75%", + } + ) + observer.observe(ref.current) + } else { + // Old browsers fallback + setImageSrc([props.src, props.srcSet]) + } + } + return () => { + didCancel = true + if (observer && observer.unobserve) { + observer.unobserve(ref.current) + } + } + }, [props.src, props.srcSet, imageSrc, ref]) + return ( - - {props.alt} - + {props.alt} ) }) diff --git a/src/components/Image/styles.css b/src/components/Image/styles.css index 5feaa95f..d0d2b622 100644 --- a/src/components/Image/styles.css +++ b/src/components/Image/styles.css @@ -1,7 +1,22 @@ +@keyframes loaded { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + .image { + width: 100%; display: block; } -.image img { - display: block; +.image.pending { + opacity: 0; +} + +.image.loaded { + animation: loaded 250ms ease-in-out; + opacity: 1; }