Estoy tratando de mostrar una cuadrícula de imágenes de Avatar. Mientras estoy en un estado de transición, me gustaría que apareciera una representación esquelética de la Imagen. Para eso estoy usando @material-ui/lab/Skeleton .

El problema que tengo es que, dado que mis imágenes están configuradas para autoescalar dentro de una cuadrícula usando height: auto, width: 100% , y la altura / longitud del contenido que se muestra debajo de la imagen varía, no hay un valor de altura establecido que Puedo pasar al componente esqueleto.

Puede ver el problema que esto causa si reduce el ancho de la pantalla de sandbox. La altura del elemento de la cuadrícula aumenta y el esqueleto circular comienza a transformarse en un óvalo.

¿Hay alguna solución aquí que pueda darme un comportamiento similar a la height: auto, width: 100% la imagen height: auto, width: 100% ?

El código completo de lo que tengo hasta ahora está debajo y en el sandbox aquí: https://codesandbox.io/s/skeleton-scaling-y00cd .

 import React from "react"; import { makeStyles } from "@material-ui/core/styles"; import Avatar from "@material-ui/core/Avatar"; import Skeleton from "@material-ui/lab/Skeleton"; import Typography from "@material-ui/core/Typography"; import clsx from "clsx"; import Grid from "@material-ui/core/Grid"; const useStyles = makeStyles(theme ={amp}gt; ({ root: { textAlign: "center", height: "100%", width: "100%" }, title: { marginTop: theme.spacing(1) }, avatarRoot: { // width: '100%', // height: 'auto', // minHeight: '273px', }, withTitle: { margin: "auto" }, img: {}, content: { lineHeight: "1.4em" }, link: { color: "inherit", textDecoration: "none" }, icon: {}, fillContainer: { height: `auto`, width: `100%`, fontSize: "4em" }, container: { marginTop: "250px" }, fallback: { height: "75%", width: "auto" }, loader: {}, avatarLoader: { height: "75%", width: "100%" }, titleLoader: { width: "60%", margin: "auto", marginTop: "8px", height: "5%" }, contentLoader: { width: "40%", margin: "auto", marginTop: "8px", height: "5%" }, testImg: { borderRadius: "100%", height: "auto", width: "100%" }, isLoading: { display: "none" }, imgContainer: { paddingTop: "100%", borderRadius: "100%", backgroundPosition: "center", backgroundSize: "contain", backgroundImage: "url(https://via.placeholder.com/500)" } })); export default function ImageAvatars() { const classes = useStyles(); return ( {amp}lt;div className={classes.root}{amp}gt; {amp}lt;Grid container spacing={1} className={classes.container}{amp}gt; {amp}lt;Grid container item xs={3} spacing={0} direction="column"{amp}gt; {amp}lt;Avatar src={"https://via.placeholder.com/500"} variant="circle" className={clsx(classes.avatarRoot, { [classes.isLoading]: false, [classes.withTitle]: true, [classes.fallback]: false, [classes.fillContainer]: true })} /{amp}gt; {amp}lt;Typography className={classes.title}{amp}gt;MUI Avatar{amp}lt;/Typography{amp}gt; {amp}lt;Typography className={classes.content}{amp}gt;test test test{amp}lt;/Typography{amp}gt; {amp}lt;/Grid{amp}gt; {amp}lt;Grid container item xs={3} spacing={0} direction="column"{amp}gt; {amp}lt;div className={classes.imgContainer} /{amp}gt; {amp}lt;div{amp}gt; {amp}lt;Typography className={classes.title}{amp}gt;background image{amp}lt;/Typography{amp}gt; {amp}lt;Typography className={classes.content}{amp}gt;test test test{amp}lt;/Typography{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;/Grid{amp}gt; {amp}lt;Grid container item xs={3} spacing={0} direction="column"{amp}gt; {amp}lt;img className={classes.testImg} src={"https://via.placeholder.com/500"} alt={"test"} /{amp}gt; {amp}lt;div{amp}gt; {amp}lt;Typography className={classes.title}{amp}gt;image el{amp}lt;/Typography{amp}gt; {amp}lt;Typography className={classes.content}{amp}gt;test test test{amp}lt;/Typography{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;/Grid{amp}gt; {amp}lt;Grid container item xs={3} spacing={0} direction="column"{amp}gt; {amp}lt;Skeleton variant="circle" className={clsx(classes.avatarLoader, classes.avatarRoot)} /{amp}gt; {amp}lt;Skeleton className={clsx(classes.titleLoader, classes.title)} /{amp}gt; {amp}lt;Skeleton className={clsx(classes.contentLoader, classes.content)} /{amp}gt; {amp}lt;/Grid{amp}gt; {amp}lt;/Grid{amp}gt; {amp}lt;/div{amp}gt; ); } 

La solución a continuación se basa en el artículo aquí: https://css-tricks.com/aspect-ratio-boxes/#article-header-id-3

La esencia de la solución es usar padding-top expresado como un porcentaje para crear un cuadro con una relación de aspecto específica (cuadrado en este caso). El relleno en porcentajes se basa en el ancho, incluso al especificar padding-top o padding-bottom, por lo que un relleno de 100% produce una altura de relleno igual al ancho.

El CSS / JSS relevante es:

  avatarSkeletonContainer: { height: 0, overflow: "hidden", paddingTop: "100%", position: "relative" }, avatarLoader: { position: "absolute", top: 0, left: 0, width: "100%", height: "100%" }, 

Esto se usa de la siguiente manera:

  {amp}lt;Grid container item xs={3} spacing={0} direction="column"{amp}gt; {amp}lt;div className={classes.avatarSkeletonContainer}{amp}gt; {amp}lt;Skeleton variant="circle" className={classes.avatarLoader} /{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;Skeleton className={clsx(classes.titleLoader, classes.title)} /{amp}gt; {amp}lt;Skeleton className={clsx(classes.contentLoader, classes.content)} /{amp}gt; {amp}lt;/Grid{amp}gt; 

Aquí está el código completo de mi modificación de su sandbox:

 import React from "react"; import { makeStyles } from "@material-ui/core/styles"; import Avatar from "@material-ui/core/Avatar"; import Skeleton from "@material-ui/lab/Skeleton"; import Typography from "@material-ui/core/Typography"; import clsx from "clsx"; import Grid from "@material-ui/core/Grid"; const useStyles = makeStyles(theme ={amp}gt; ({ root: { textAlign: "center", height: "100%", width: "100%" }, title: { marginTop: theme.spacing(1) }, withTitle: { margin: "auto" }, content: { lineHeight: "1.4em" }, link: { color: "inherit", textDecoration: "none" }, fillContainer: { height: `auto`, width: `100%`, fontSize: "4em" }, container: { marginTop: "250px" }, fallback: { height: "75%", width: "auto" }, avatarSkeletonContainer: { height: 0, overflow: "hidden", paddingTop: "100%", position: "relative" }, avatarLoader: { position: "absolute", top: 0, left: 0, width: "100%", height: "100%" }, titleLoader: { width: "60%", margin: "auto", marginTop: "8px", height: "5%" }, contentLoader: { width: "40%", margin: "auto", marginTop: "8px", height: "5%" }, testImg: { borderRadius: "100%", height: "auto", width: "100%" }, isLoading: { display: "none" }, imgContainer: { paddingTop: "100%", borderRadius: "100%", backgroundPosition: "center", backgroundSize: "contain", backgroundImage: "url(https://via.placeholder.com/500)" } })); export default function ImageAvatars() { const classes = useStyles(); return ( {amp}lt;div className={classes.root}{amp}gt; {amp}lt;Grid container spacing={1} className={classes.container}{amp}gt; {amp}lt;Grid container item xs={3} spacing={0} direction="column"{amp}gt; {amp}lt;Avatar src={"https://via.placeholder.com/500"} variant="circle" className={clsx(classes.avatarRoot, { [classes.isLoading]: false, [classes.withTitle]: true, [classes.fallback]: false, [classes.fillContainer]: true })} /{amp}gt; {amp}lt;Typography className={classes.title}{amp}gt;MUI Avatar{amp}lt;/Typography{amp}gt; {amp}lt;Typography className={classes.content}{amp}gt;test test test{amp}lt;/Typography{amp}gt; {amp}lt;/Grid{amp}gt; {amp}lt;Grid container item xs={3} spacing={0} direction="column"{amp}gt; {amp}lt;div className={classes.imgContainer} /{amp}gt; {amp}lt;div{amp}gt; {amp}lt;Typography className={classes.title}{amp}gt;background image{amp}lt;/Typography{amp}gt; {amp}lt;Typography className={classes.content}{amp}gt;test test test{amp}lt;/Typography{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;/Grid{amp}gt; {amp}lt;Grid container item xs={3} spacing={0} direction="column"{amp}gt; {amp}lt;img className={classes.testImg} src={"https://via.placeholder.com/500"} alt={"test"} /{amp}gt; {amp}lt;div{amp}gt; {amp}lt;Typography className={classes.title}{amp}gt;image el{amp}lt;/Typography{amp}gt; {amp}lt;Typography className={classes.content}{amp}gt;test test test{amp}lt;/Typography{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;/Grid{amp}gt; {amp}lt;Grid container item xs={3} spacing={0} direction="column"{amp}gt; {amp}lt;div className={classes.avatarSkeletonContainer}{amp}gt; {amp}lt;Skeleton variant="circle" className={classes.avatarLoader} /{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;Skeleton className={clsx(classes.titleLoader, classes.title)} /{amp}gt; {amp}lt;Skeleton className={clsx(classes.contentLoader, classes.content)} /{amp}gt; {amp}lt;/Grid{amp}gt; {amp}lt;/Grid{amp}gt; {amp}lt;/div{amp}gt; ); } 

Editar escala de esqueleto