CSS – background and styling img

前言

之前写过一些: 

W3Schools 学习笔记 (2) – CSS Image Sprites

W3Schools 学习笔记 (3) – CSS Styling Images & CSS Multiple Backgrounds

这篇作为整理.

 

Styling img

default behavior

img width: auto, height: auto 情况下, 会依据图片的 original size 渲染图片.

<div class="container">
  <img src="./images/tifa2.PNG" />
</div>

效果

红色框是 container 的大小. 图片超过了.

max-width 100%

所以通常 Tailwind, Bootstrap 它们的 base.css 都会给图片设定一个 max-width:100%

width: 100% 配上 height : auto, 图片会按原图的比例缩小(或放大).

width, height: 100%

有些情况下, 希望图片完全覆盖框. 也就是说比例会被改变.

img {
  width: 100%;
  height: 100%;
}

效果

由于, 图片本来的比例是 16:9, 而被强行塞入一个 1:1 的框里, 它就变形了.

object-fit: contain

object-fix 就是用来调整它变形的. 

object-fit: contain;

contain 的意思就是把图片完整的塞入, 但是不变形, 而是留白. 好处是图片信息还在, 坏处是留白.

object-fit: cover

完整图 --> 

cover 没有造成留白, 但是图片信息却丢失了. 它只能保留一部分

它的步骤是先把图片压缩 (依据比例选择 width, height 其中一边来压缩), 比如上面这个是压缩高度.

图片 vertical 的信息被保留了, 那 horizontal 就需要被牺牲掉. 我们可以通过 position 来控制要牺牲掉那些部分, 比如选 center, 那就丢失掉左右的内容.

如果图片小于框, 那么就不是压反而是拉 (图片会变蒙). 比例依旧保留同样部分需要牺牲.

 

左图的高度是 392 x 761, 右图是 1000 x 761

高度不变, 但是 width 增加了. 可以看到被拉升后图片蒙了, 而且上下的信息也丢失了, 只剩下中间的部分 (我设置了 position: center)

object-position: horizontal vertical

object-position: 70% 0;

通常是用 % 来控制的. 由于 cover 肯定是压缩其中一边, 所以 horizontal vertical 也只需要调 1 边而已. (它的默认是 0% 0%, 还有一种写法是 center, 表示 50% 50%, 在这个情况下和 50% 0 是一样的效果)

它的 percent 算法是这样的

第一张是效果图, 第二张是解释它如果从 70% 开始 cut. 

object-fit: fill

这个就是默认值, 也就是图片会变形.

object-fit: none

跟 cover 有点像, 只是它不会压小, 它就直接 clip 中间.

这时也是可以用 object-position 来调整. 通常这时就是调 2 边 holizontal 和 vertical

object-fit: none;
object-position: 70% 0%;

效果

它的算法是这样的: 

假设图片 width 是 1349px. 框是 250px

那么 1349 - 250 = 1099px, 这个就是 0-100% 的 range.

除于 100 得到 10.99px = 1%

所以用 px 来表达的话是 70 * 10.99px = 769.3px (记得要用 negative value, 不然方向会错)

object-position: -769.3px 0%;

效果是一模一样的.

filters

img {
  filter: grayscale(100%); /* 黑白照 */
  filter: blur(4px); /* 变萌 */
}

还有许多 effects, 但常用的就只有上面 2 个, 更多参考.

Flip Image

镜子效果是通过 scaleX 来做的.

img:hover {
  transform: scaleX(-1);
}

 

width and height attribute & aspect-ratio

参考: Setting Height And Width On Images Is Important Again (必读)

上面讲到的都是 CSS styling. 而且很多时候是等到图片加载后依据它的比例渲染

这会导致首屏渲染不完整, 图片加载后会跳, 术语叫 layout shift.

用户体验扣分, 同时 layout resize 也会导致 reflow 性能也扣分.

比较好的做法是在图片加载之前就设定好一个 frame.

早年的做法是做一个 image container 然后利用 padding 模拟 aspect ratio 的方式做出一个 aspect ratio 的 frame, 后来直接用 CSS4 的 aspect ratio 也可以.

在到现在直接利用 img 的 width 和 height attribute 就可以了. 它的发展史是比较坎坷的, 想深入了解就看上面的文章

下面我们来一个一个看. 别搞混就可以了.

1. no width and height attribute

没有设置 width height attribute, 只设置 CSS width: 100% (假设 parent 是 500px) 的情况下.

左图是图片加载后的效果, 右图是图片加载前的效果 (我用 404 来替代). 红框是图片的 outline (我们每次都关注加载前和加载后的渲染情况)

加载前整体的 height 是很小的, 图片加载后 height 就大了, 这就是所谓的 layout shift.

2. width height attribute

为 img 添加上 attribute wdith: 100; height: 100 (它的 unit 是 px)

渲染后的效果图片变形了. 另外这个比例是 100% width (来自 CSS) + 100px height (来自 attribute). 而不是依据图片的比例 (哪怕是图片加载以后)

3. CSS height auto

上面是不正确的做法. 当 img 加上 width height attribute 以后, CSS 一定要 set height auto

加了 height auto 后, 图片加载后渲染是正确了 (依据图片的比例), 图片加载前, 它的渲染逻辑是这样的 

attribute width:100 和 height: 100 被当作一个 aspect ratio.

然后配合 CSS 的 width 100% 去做渲染. 而不是直接渲染成 100x100px 哦

而当图片加载后, 它会改成用图片的 aspect ratio 做渲染. 这种情况它依然会跳一下.

跳一下当然是不对的, 所以绝大部分的情况下, img width height 一定是放图片本身的 aspect ratio, 而这个 ratio 也是最终想渲染出来的 radio.

 

4. 2022 年该怎样用? 

a. 不要用 padding aspect ratio 或者 CSS4 aspect ratio 方案去画 frame (除非图片本身的 ratio 不是你想展现的 ratio)

b. 不要用 intrinsicsize attribute (这个是以前历史过渡采用的方案)

c. 用 attribute width height 作为图片加载前, frame 渲染的 aspect ratio, 同时 CSS set 其中一边的 dimension 比如 max-width: 100%. 另一 side 就设置 auto. 

d. picture > source 也是有 width height 的哦. 它和 img 的玩法是一样的. 所以可以实现不同 media query 下输出不同的图片 aspect ratio 解决 art direction 的问题.

没有设置 source 的 width height 那么会 fallback 去拿 img 的 width height 哦.

最后补上一个 RWD Image 的版本

<picture>
  <source
    media="(min-width: 1000px)"
    srcset="https://via.placeholder.com/600x600"
    width="1600"
    height="1600"
  />
  <source
    media="(min-width: 500px)"
    srcset="https://via.placeholder1.com/300x300"
    width="1600"
    height="900"
  />
  <img
    class="img"
    src="https://via.placeholder1.com/300x300"
    width="100"
    height="100"
  />
</picture>
View Code

 

<img> extra 4px at the bottom

参考: 冷知识 (新手) – <img> extra 4px at the bottom

 

background-image

default behavior

background-image 默认就类似有了 img width, height: 100% 的概念. 它是不会超出 container 的 (废话不然它怎么是 background).

default 它的效果是 object-fit: none

background-size and background-position

它和 image 的 object-fit 和 object-position 基本是一样的

background-image: url("./images/tifa2.PNG");
background-size: cover;
background-position: 70% 0;

通常用在 background-image 大于 container 的情况,

但是, 当 background-image 小于 container 的时候. position 的功能就变成了定位.

section {
  margin-top: 10rem;
  height: 500px;
  width: 100%;
  background-image: url('./images/car.png');
  background-repeat: no-repeat;
  background-position: 50px 50px;
  border: 1px solid red;
}

效果

background-size % percentage

特别说一下, 除了 cover, contain. background-size 也常用 percentage 做一些 effect. 它的定义是这样的.

.box {
  width: 300px;
  height: 50px;
  background-image: linear-gradient(to right, red, yellow);
}

效果

如果设置了 background-size: 50% 效果是这样的

框 300px, 但是 background 只有 50%, 也就是 150px.

那么就会有空洞, 于是 background 就 repeat 了 (因为默认 background 就是会 repeat 的)

同理如果设置称 background-size: 200%, 效果如下:

背景比框长了一倍, 所以黄色的部分就少了, 它相等于只拿了原本的 150px 的部分来显示在 300px 的框内.

background-repeat

当图片比 container 小, 默认情况下它会自动重复. 可以 set 成 no-repeat, x-repeat, y-repeat, repeat 来控制它.

background-attachment

和 repeat 一样用在当图片比 container 小的时候

scroll 图片会随着 scroll 一起移动, 效果就类似 position absolute

fixed 图片会随着 viewport scroll 一起移动, 效果类似 position fixed

local 默认值, 图片不会随着 scroll 移动, 类似 position static

multiple background-image

background image 是可以 multiple 的

用逗号分开 1, 2

越靠前的越在上层, 用户越看见.

shorthand 的写法

一个常用的地方是 background + overlay

一个 linear-gradient 作为 overlay 的黑, 在加一张图片

background-origin

set background image render 的位置

.container {
  outline: 5px solid red;
  border: 1rem solid transparent;
  padding: 1rem;
  width: 300px;
  height: 300px;

  background-image: url("./images/tifa2.PNG");
  background-repeat: no-repeat;
  background-origin: border-box;
  background-size: cover;
}

border-box, 从 border 开始

boder 要 transparent 才看的出来. (红色是 outline 哦)

padding-box (default), 从 padding 开始

粉红色是 border 的颜色

content-box, 从内容开始

白色是 padding

 

background-clip

它和 origin 类似. 但 origin 只能用来设置 background-image.

clip 可以设置 background-color 和 image, 而且除了 border-box, padding-box, content-box 它还有一个 text

border-box (default), 从 border 开始

h1 {
  outline: 5px solid red;
  border: 3rem solid transparent;
  padding: 3rem;
  font-size: 4rem;
  color: transparent;
  width: fit-content;
  background-color: blue;
  -webkit-background-clip: border-box;
}

 效果

和 image 不同, color 的范围是从 border-box 开始的

padding-box, 从 padding 开始

粉红色是 border

content-box, 从内容开始

白色是 padding

它可以用来实现 silider dot dot dot 的设计

.dot-list {
  padding: 1rem;

  display: flex;
  flex-direction: column;
  gap: 2rem;

  .dot {
    border-radius: 50%;
    padding: 6px;
    width: 20px;
    height: 20px;
    background-color: red;
    background-clip: content-box;

    &:last-child {
      border: 2px solid red;
      padding: 4px;
    }
    &:first-child {
      padding: 4px;
    }
  }
}
View Code

text

h1 {
  outline: 5px solid red;
  font-size: 8rem;
  color: transparent;
  width: fit-content;
  background-image: url("./images/tifa2.PNG");
  background-size: cover;
  -webkit-background-clip: text;
}

clip color 和 image 都有效, 通常 text 是配上 image url 或者 gradient. 记得 color 要 transparent 哦.

最好加上 -webkit-background-clip, 和用 -webkit-text-fill-color

参考: 

Youtube – Top 10 CSS Tricks You Didn't Know!

stackoverflow – Difference between "-webkit-text-fill-color" and "color"?

 

Gradients

Gradients 是渐变 color

3 大种类:

Linear Gradients (goes down/up/left/right/diagonally)

Radial Gradients (defined by their center)

Conic Gradients (rotated around a center point)

Linear Gradients

background-image: linear-gradient(to left, red, yellow);

它是 background-image 来的哦, 不是 color

最少 2 种颜色才能渐变.

默认是 top to bottom, 有很多 pattern, 比如 left to right, diagonal (对角线), degree 等

background-image: linear-gradient(to right, red 50%, yellow);

red 50% 从开始一直是纯红色到 50%, 然后渐变去黄色

background-image: linear-gradient(to right, red 25%, yellow 50%);

表示开始到 25% 纯红, 然后渐变去黄, 从 50% 的位置开始变成纯黄

除了 to left, to right 还可以做斜角 135deg

Radial Gradients

radial 就是画圈

background-image: radial-gradient(circle at center, red, yellow);

效果

从中心点以圆圈的形状往外渐变

我们还可以指定圆圈的直径和起始点

background-image: radial-gradient(100px at 30% 50%, red, yellow);

效果

x, y 是起始点的坐标,100px 是直径。红色会从最里面渐变到直径完,然后圆圈外都是黄色。

挖洞效果

background-image: radial-gradient(circle at center, red 50px, blue 51px);

red 50px 表示从 0 - 50 用纯红

blue 51px 表示从 51 - end 用纯蓝

50 - 51 则是从红到蓝的渐变。如果没有这 1 px 会很突兀。

如果我们把 red 换成 transparent 那就变成类似中间挖了一个洞的效果。

Conic Gradients

 

 

Blend Mode

参考:

混合模式 mix-blend-mode/background-blend-mode

借助 mix-blend-mode 纯CSS制作文字镂空效果

Different result when using mix-blend-mode and background-blend-mode

Creative CSS Mix Blend Mode text effect | mix-blend-mode | CSS

例子 1

Blend Mode 可以做出以下的效果

CSS Style

.container {
  background-image: url("./images/tifa2.PNG"),
    linear-gradient(135deg, red, yellow);
  background-size: cover;
  width: 40%;
  height: 50vh;
  background-blend-mode: screen;
}

例子 2

当有多张背景图或者颜色的时候就可以使用 background-blend-mode 来表示它们重贴后的特效.

CSS Style

body {
  font-size: 8rem;
  font-weight: 700;
  color: black;

  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;

  position: relative;
  &::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 50%;
    height: 100%;
    background-color: white;
  }

  &::after {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    width: 50%;
    height: 100%;
    background-color: black;
    z-index: -1;
  }
}

marquee {
  color: white;
  mix-blend-mode: difference;
}
View Code

mix-blend-mode 和 background-blend-mode 唯一的区别是, mix-blend-mode 是用在不同的 element 重叠, 而 background-blend-mode 是用同一个 element 但多张 background-image 或者和 background-color 重叠.

例子 3

文字镂空效果, 不一定要用 clip text.

CSS Style

.container {
  width: 50%;
  height: 70vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background-image: url("./images/tifa2.PNG");
  background-size: cover;
}

h1 {
  font-size: 8rem;
  background-color: white;
  color: black;
  mix-blend-mode: screen;
}

Figma 也是有这个功能哦

Font color depend on background

它的效果中有一个是 different, 可以用来做背景色和字体颜色, 但要注意, 它的 color 并不是 black and white 而是补色哦.

其它做法:

Switch font color for different backgrounds with CSS

Top 10 CSS Tricks You Didn't Know!

做 dark mode 的方式

filter: invert(1) 能把所有子层颜色反转, background-color 和 color 都会哦. 

body {
  width: 50vw;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 4rem;
  background-color: black;
  filter: invert(1);
}

.box1 {
  background-color: red;
  width: 100px;
  height: 100px;
}

 

mask-image

参考: YouTube – mask-image lets you do some really cool stuff

效果

一张图片,我们在上面放一个形状 (SVG),它会依据这个形状 clip 图片。

img {
  width: 640px;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  mask-image: url('../../src/icons/solid-car-side.svg');
  mask-repeat: no-repeat;
  mask-size: contain;
  mask-position: center;
}

注: 目前游览器兼容还不理想,需要加上 -webkit prefix,当然如果有使用 postcss-preset-env 就不需要烦恼这些啦。

它的语法和 background-image 非常类似,也是有 size, position, repeat 等等。

gradient

除了 SVG,mask-image 也支持 gradient 写法。

但是 gradient 的颜色只能是 transparent 和 black。

transparent 的部分最终会被 clip 掉。black 则会被保留起来。

.container {
  background-color: red;

  img {
    width: 640px;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    mask-image: radial-gradient(50px at 30% 40%, transparent 100%, black);
  }
}

效果

我用 gradient 在 x:30%,y:40% 坐标上画了一个 50px 直径的圆圈,并且它的颜色是 transparent。于是这个部分被 clip 掉了。

最终显示了背景的红色。

题外话: mask-image 也可以 apply 在普通的 div 上,并不一定是 img element。

 

posted @ 2022-02-25 12:56  兴杰  阅读(171)  评论(0编辑  收藏  举报