javascript - 在可变高度网格行中处理@material-ui骨架缩放的好方法?

标签 javascript html css reactjs material-ui

我正在尝试显示头像图像的网格。在过渡状态下,我希望出现图像的骨架表示。为此,我正在使用 @material-ui/lab/Skeleton

我遇到的问题是,因为我的图像设置为使用 height: auto, width: 100% 在网格内自动缩放,以及显示在图像各不相同,没有我可以传递给骨架组件的设置高度值。

如果您缩小沙盒屏幕的宽度,就会看到这导致的问题。网格元素的高度增加导致圆形骨架开始变形为椭圆形。

这里是否有一个解决方案可以使我的行为类似于图像的 height: auto, width: 100%

到目前为止,我所拥有的完整代码在下方和此处的沙箱中: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 => ({
  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 (
    <div className={classes.root}>
      <Grid container spacing={1} className={classes.container}>
        <Grid container item xs={3} spacing={0} direction="column">
          <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
            })}
          />
          <Typography className={classes.title}>MUI Avatar</Typography>
          <Typography className={classes.content}>test test test</Typography>
        </Grid>
        <Grid container item xs={3} spacing={0} direction="column">
          <div className={classes.imgContainer} />
          <div>
            <Typography className={classes.title}>background image</Typography>
            <Typography className={classes.content}>test test test</Typography>
          </div>
        </Grid>
        <Grid container item xs={3} spacing={0} direction="column">
          <img
            className={classes.testImg}
            src={"https://via.placeholder.com/500"}
            alt={"test"}
          />
          <div>
            <Typography className={classes.title}>image el</Typography>
            <Typography className={classes.content}>test test test</Typography>
          </div>
        </Grid>
        <Grid container item xs={3} spacing={0} direction="column">
          <Skeleton
            variant="circle"
            className={clsx(classes.avatarLoader, classes.avatarRoot)}
          />
          <Skeleton className={clsx(classes.titleLoader, classes.title)} />
          <Skeleton className={clsx(classes.contentLoader, classes.content)} />
        </Grid>
      </Grid>
    </div>
  );
}

最佳答案

以下解决方案基于此处的文章:https://css-tricks.com/aspect-ratio-boxes/#article-header-id-3

解决方案的要点是使用以百分比表示的 padding-top 来创建具有特定纵横比的框(在本例中为正方形)。百分比填充基于宽度,即使在指定 padding-top 或 padding-bottom 时也是如此,因此 100% 的 padding-top 会产生等于宽度的填充高度。

相关的 CSS/JSS 是:

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

然后按如下方式使用:

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

这是我修改你的沙箱的完整代码:

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 => ({
  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 (
    <div className={classes.root}>
      <Grid container spacing={1} className={classes.container}>
        <Grid container item xs={3} spacing={0} direction="column">
          <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
            })}
          />
          <Typography className={classes.title}>MUI Avatar</Typography>
          <Typography className={classes.content}>test test test</Typography>
        </Grid>
        <Grid container item xs={3} spacing={0} direction="column">
          <div className={classes.imgContainer} />
          <div>
            <Typography className={classes.title}>background image</Typography>
            <Typography className={classes.content}>test test test</Typography>
          </div>
        </Grid>
        <Grid container item xs={3} spacing={0} direction="column">
          <img
            className={classes.testImg}
            src={"https://via.placeholder.com/500"}
            alt={"test"}
          />
          <div>
            <Typography className={classes.title}>image el</Typography>
            <Typography className={classes.content}>test test test</Typography>
          </div>
        </Grid>
        <Grid container item xs={3} spacing={0} direction="column">
          <div className={classes.avatarSkeletonContainer}>
            <Skeleton variant="circle" className={classes.avatarLoader} />
          </div>
          <Skeleton className={clsx(classes.titleLoader, classes.title)} />
          <Skeleton className={clsx(classes.contentLoader, classes.content)} />
        </Grid>
      </Grid>
    </div>
  );
}

Edit Skeleton scaling

关于javascript - 在可变高度网格行中处理@material-ui骨架缩放的好方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59461615/

相关文章:

javascript - 使用字符串访问数组中的对象

javascript - 使用 ng-describe 与 Protractor 进行端到端测试

Javascript 行为异常

html - CSS 向左浮动并位于图像下方

javascript - Bootstrap - 响应式搜索按钮

javascript - 获取坐标事件 map openlayers 4.6.5 ~ 5

html - 如何在 CSS 中悬停时显示隐藏内容

html - 建立链接,没有 "a href"也没有 JS

jQuery 工具 - 垂直选项卡可能吗?

javascript - 使用范围变量定义时,ng-class 在 AngularJS 中不起作用