Skip to content

Instantly share code, notes, and snippets.

@Salemsky
Created February 12, 2025 13:03
Show Gist options
  • Save Salemsky/1414e5e7fd6839eb4904afadf3dfe59c to your computer and use it in GitHub Desktop.
Save Salemsky/1414e5e7fd6839eb4904afadf3dfe59c to your computer and use it in GitHub Desktop.
sc image hover effect
import { styled } from 'styled-components';
import { hoverEffect } from './hover-effect.ts';
import { Image } from './Image.tsx';
const Wrapper = styled.div`
display: flex;
width: 600px;
margin: 20px auto 20px auto;
`;
const ImageItem = styled.div`
display: flex;
position: relative;
width: 100%;
${Image.selector} {
margin: 0 10px;
}
&:first-child {
${hoverEffect.scaleUp(Image.selector)}
}
&:last-child {
${hoverEffect.scaleDown(Image.selector)}
}
`;
const Example = (): import('react').ReactElement => {
return (
<Wrapper>
<ImageItem>
<Image src="" />
</ImageItem>
<ImageItem>
<Image src="" />
</ImageItem>
</Wrapper>
);
};
const ZOOM_UP = 1;
const ZOOM_DOWN = 1.03;
const scale = (selector: string, from: number, to: number): string => {
return `
${selector} {
overflow: hidden;
}
${selector} > * {
transform: scale3d(${from}, ${from}, 1);
transition: .2s ease-in-out;
@media (hover: hover) and (pointer: fine) {
&:hover {
transform: scale3d(${to}, ${to}, 1);
}
}
}
`;
};
export const hoverEffect = {
scaleUp: (selector: string): string => scale(selector, ZOOM_UP, ZOOM_DOWN),
scaleDown: (selector: string): string => scale(selector, ZOOM_DOWN, ZOOM_UP),
};
import { styled } from 'styled-components';
type Props = Readonly<
Pick<import('react').ComponentProps<'img'>, 'src'> & {
aspectRatio?: number | undefined;
}
>;
const StyledImage = styled.div.withConfig({
shouldForwardProp: (p) => !['aspectRatio'].includes(p),
})<Required<Pick<Props, 'aspectRatio'>>>`
position: relative;
width: 100%;
aspect-ratio: ${({ aspectRatio }): number => aspectRatio};
& > * {
position: absolute;
left: 0;
top: 0;
max-width: 100%;
height: 100%;
}
`;
export const Image = ({
aspectRatio = 1,
src,
}: Props): import('react').ReactElement => {
return (
<StyledImage aspectRatio={aspectRatio}>
<img src={src} />
</StyledImage>
);
};
Image.selector = StyledImage.toString();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment