css实现单图和多图的不同展示规则

168 阅读3分钟

设计小哥哥说,这次需求有点复杂哦! 我心想,不就是样式吗?能有多复杂?再复杂的样式不过多些几行而已! 等我拿到设计图的时候,发现是真复杂啊!

图片区域分为单图和多图。

  • 单图情况
    • 正常图 160x160
    • 超宽图 长边160,高为宽边的3/8
    • 超高图 高边160,宽为高边的3/8
  • 多图情况 80x80

我一看这么复杂,根本不想用css来写了,还是用js吧。

function computeImageStyle(imgs) {
    const maxSize = 160; // 单张图片的最大宽高
    const normalSize = 80; // 两张及以上的图片宽高
    const imageStyle = {};
    if (imgs.length >= 2) {
        imageStyle.width = normalSize + 'px';
        imageStyle.height = normalSize + 'px'
    } else {
        const { width, height } = imgs[0];
        let finalWidth = 'auto';
        let finalHeight = 'auto';
        if (width > 8 * height / 3) {
            // 超宽图
            finalWidth = maxSize;
            finalHeight = Math.floor((finalWidth * 3) / 8);
        } else if (height > 8 * width / 3) {
            // 超高图
            finalHeight = maxSize;
            finalWidth = Math.floor((finalHeight * 3) / 8);
        } else if (width > height) {
            finalWidth = maxSize;
        } else {
            finalHeight = maxSize;
        }
        imageStyle.width = typeof finalWidth === 'number' ? finalWidth + 'px' : finalWidth;
        imageStyle.height = typeof finalHeight === 'number'
            ? finalHeight + 'px'
            : finalHeight;
    }
    return imageStyle;
}

当我写完还是很得意的,哼,小需求小需求~

等到我提交代码的时候,我们组的大佬说用css写就好了,我🤯惊呆,果然一年过去了,我还是那个小菜鸡。

仔细研究了一下大佬的代码,我知道了关键点就在css的属性:only-child上,这个属性的意思是没有任何兄弟元素的元素。

利用这个:only-child属性,就可以很好的区分单图和多图的情况下。多图的情况比较简单,不用多说。那怎么处理单图的三种情况呢?

噔噔噔,还是得js出马。用js对比图片的宽高,如果是超高图,给超高图的样式;如果是超宽图,给超宽图的样式。

话不多说,直接看代码

.imgs_wrp {
  display: flex;
}

.img_item {
  width: 80px;
  height: 80px;
  background-position: 50% 50%;
  background-size: cover;
  object-fit: cover;
  
  // 如果有相邻左的节点,添加左间距
  &+& {
    margin-left: 4px;
  }
  
  // 单图默认宽高相等
  &:only-child {
    width: 160px;
    height: 160px;
    
    // 超宽图的高为宽的3/8
    &.img_item_lw {
      height: auto;
      min-height: ~"calc(160px * 3 / 8)";
    }
    
    // 超高图的宽为高的3/8
    &.img_item_lh {
      width: auto;
      min-width: ~"calc(160px * 3 / 8)";
    }
  }
}

最终效果如下

题外话

除了用:only-child,还可以用一个非常神奇的属性:first-child:last-child替代。看着这个属性很绕,解释一下,就是既是第一个又是最后一个元素。什么情况下第一个会是最后一个呢?不就是只有一个元素的情况嘛!

这个属性太绕了,不好好想想都想不清楚,最好不要写,容易挨打。 如果想挨更毒的打,也可以写:nth-child(1):nth-last-child(1)

完整代码

如果想亲自尝试一下,可以用下面的完整代码。在codepen里就可以跑起来了。

html部分

<div class="blocks">
  <div>
    <h1>单图</h1>
    <div class="imgs_wrp">
      <img
        class="img_item"
        src="https://i.pinimg.com/564x/f8/1a/74/f81a74e6a15329c0343ba6279ccaeb6f.jpg"
      />
    </div>
  </div>
  <div>
    <h1>多图</h1>
    <div class="imgs_wrp">
      <img
        class="img_item"
        src="https://i.pinimg.com/564x/f8/1a/74/f81a74e6a15329c0343ba6279ccaeb6f.jpg"
      />
      <img
        class="img_item"
        src="https://img95.699pic.com/xsj/0r/r9/pc.jpg!/fw/700/watermark/url/L3hzai93YXRlcl9kZXRhaWwyLnBuZw/align/southeast"
      />
    </div>
  </div>
  <div>
    <h1>超宽图</h1>
    <div class="imgs_wrp">
      <img
        class="img_item img_item_lw"
        src="https://img95.699pic.com/xsj/0r/r9/pc.jpg!/fw/700/watermark/url/L3hzai93YXRlcl9kZXRhaWwyLnBuZw/align/southeast"
      />
    </div>
  </div>
  <div>
    <h1>超高图</h1>
    <div class="imgs_wrp">
      <img
        class="img_item img_item_lh"
        src="https://i.pinimg.com/564x/f8/1a/74/f81a74e6a15329c0343ba6279ccaeb6f.jpg"
      />
    </div>
  </div>
</div>

css部分

.blocks {
  display: flex;
  gap: 30px;
}
.imgs_wrp {
  display: flex;
}

.img_item {
  width: 80px;
  height: 80px;
  background-position: 50% 50%;
  background-size: cover;
  object-fit: cover;
  
  // 如果有相邻左的节点
  &+& {
    margin-left: 4px;
  }
  
  // 单图默认宽高相等
  &:only-child {
    width: 160px;
    height: 160px;
    
    // 超宽图的高为宽的3/8
    &.img_item_lw {
      height: auto;
      min-height: ~"calc(160px * 3 / 8)";
    }
    
    // 超高图的宽为高的3/8
    &.img_item_lh {
      width: auto;
      min-width: ~"calc(160px * 3 / 8)";
    }
  }
}