前端开发人员在构建网站时须要作出的决定之一就是添加图片的技术。它能够是HTML <img>
,也能够是经过CSS背景生成的图片,也能够是SVG <image>
。选择正确的技术很重要,而且能够在性能和可访问性方面发挥巨大做用。css
在这篇文章中,咱们除了提到各类包含图片的方法外,还将了解到每种方法的优势和缺点,以及何时和为何要使用每种方法的前因后果。html
<Img>
元素最简单的状况下,图片元素必须包含 src
属性。前端
<img src="cool.jpg" alt="">
在页面加载时,它们会在页面图片加载时发生一些布局变化。为了不这种状况,咱们能够设置 width
和 height
属性:git
<img src="cool.jpg" width="200" height="100" alt="">
虽然对某些人来讲,这可能看起来有点过期,但它是有用的。让咱们用图片来清楚地理解这个概念:github
你注意到了吗,右边的图片即便尚未加载也会保留其空间吗?这是由于宽度和高度已经设置好了。它有明显的区别!web
Demo后端
能够用CSS隐藏图片,可是它仍然会被加载到页面中。所以,在执行此操做时请当心,若是一个图片应该被隐藏,那么它多是出于装饰的目的。浏览器
img { display: none; }
一样,以上内容也不会阻止浏览器加载图片,即便该图片在视觉上是隐藏的。缘由是 <img>
被视为替换元素,所以咱们没法控制其加载的内容。安全
HTML图片应该经过将 alt
属性设置为有意义的描述来访问,这对屏幕阅读器用户来讲是很是有帮助的。前端工程师
可是,若是不须要 alt
描述,请不要删除,若是删除了就会读出图片的src
!这对可访问性(无障碍)环境是很是不利的。
不只如此,若是图片由于某种缘由没有加载,而且它有一个明确的 alt
,它将做为一个备用值回退显示。既然有一些有趣的事情我想让你们知道,那咱们就从视觉上说说吧。
咱们有如下图片:
<img class="food-thumb" width="300" height="200" src="cheescake.jpg"> <img class="food-thumb" width="300" height="200" src="cheescake.jpg" alt="">
src
无效,图片没有正常加载。第一个没有 alt
属性,而第二个是空的 alt
属性。你能期待这个视觉效果吗?
没有 alt
的图片仍然保留其空间,这很混乱,而且对可访问性不利。虽然另外一个折叠了,以适应其空的 alt
属性的内容,但因为它的边框,致使了它做为一个小点出现。
可是,当存在 alt
属性值时,它将以下所示:
这不是很好的反馈吗?另外,当图片源发生故障时,能够向其中添加伪元素。
<img>
的优势在于,能够针对特定视口大小将其扩展为具备多个版本的图片。例如,这可用于商品图片。
咱们有两种不一样的方式来生成一组响应式图片:
srcset
属性<img src="small.jpg" srcset="medium.jpg 500w, large.jpg 800w" alt="">
这是一个简单的例子。对我来讲,我不认为使用 srcset
是根据屏幕宽度显示多个图片大小的完美解决方案。只能让浏览器选择合适的图片,而咱们对此无能为力。
<picture> <source srcset="large.jpg" media="(min-width: 800px)" /> <source srcset="medium.jpg" media="(min-width: 500px)" /> <img src="small.jpg" /> </picture>
另外一种选择是使用 <picture>
元素。我更喜欢这种方式,由于它更容易预测。
咱们可使用 <img>
的一大优势就是 object-fit
和 object-position
属性。它们让咱们能够控制 <img>
的内容如何调整大小和位置,就像CSS背景图片同样。
object-fit 的可能值为:fill,contain,cover,none,scale-down
能够这样使用:
img { object-fit: cover; object-position: 50% 50%; }
如今,咱们已经介绍了 <img>
元素,是时候继续探索第二种技术了。
当使用CSS背景显示图片时,它须要一个具备内容或特定宽度或高度的元素。一般,背景图片的主要用途应该是用于装饰目的。
简单来讲,咱们须要一个元素。
<div class="element">Some content</div>
.element { background: url('cool.jpg'); }
使用CSS背景图片的好处是能够轻松地控制多个背景。考虑下面的例子:
.element { background: url('cool-1.jpg'), url('cool-2.jpg'); }
咱们能够在特定的视口上隐藏和显示图片,而不会让图片被下载。若是图片没有用CSS设置,就不会被下载。这是比使用 <img>
更多的好处。
@media (min-width: 700px) { .element { background: url('cool-1.jpg'); } }
在上面的示例中,咱们有一个背景图片,仅在视口宽度大于 700px
时显示。
若是使用不正确,背景图片会对无障碍浏览不利。例如,将其用于文章的大拇指,这对文章相当重要。
你可能会以为颇有趣,可是普通人知道,若是要保存图像,只需单击鼠标左键,而后选择保存便可。CSS背景图片并不是如此。您必须先检查元素,而后在DevTools中的 url
中打开连接,而后才能下载随CSS添加的图像。
可使用伪元素与CSS背景图片一块儿使用,例如,在图片的顶部显示一个叠加元素。对于 <img>
来讲,除非咱们为覆盖层添加一个单独的元素,不然没法作到这一点。
<Image>
SVG被认为是图像,它的最大功能在于缩放而不影响质量。另外,使用SVG,咱们能够嵌入 JPG
,PNG
或 SVG
图像。请参见下面的HTML:
<svg width="200" height="200"> <image href="cheesecake.jpg" height="100%" width="100%" preserveAspectRatio="xMidYMid slice" /> </svg>
你是否注意到了 prepareAspectRatio
?这样一来,可使图像占据SVG的整个宽度和高度,而不会被拉伸或压缩。
当 <image>
宽度较大时,它将填充其父级(SVG)宽度而不会拉伸。
这很是相似于CSS中的 object-fit:cover
或 background-size:cover
。
关于SVG的可访问性,这使我想起了 <title>
元素。例如,咱们能够像下面这样添加它:
<svg width="200" height="200"> <title>A photo of blueberry Cheescake</title> <image href="cheesecake.jpg" height="100%" width="100%" preserveAspectRatio="xMidYMid slice" /> </svg>
咱们甚至可使用 <desc>
元素:
<svg width="200" height="200"> <title>A photo of blueberry Cheescake</title> <desc>A meaningful description about the image</desc> <image href="cheesecake.jpg" height="100%" width="100%" preserveAspectRatio="xMidYMid slice" /> </svg>
在检查元素并复制图像的URL以前,不可能下载嵌入到SVG中的图像。然而,若是咱们想要阻止用户下载特定的图像,这多是一件好事。至少,它将减小下载图像的机会很容易。
在构建 hero section 时,咱们有时须要在标题和其余内容下面有一个图像。以下图所示:
注意这里有一个图像。你将如何构建它?好吧,让我先补充一些要求:
在开始解决方案以前,让咱们先问问本身这种背景的性质。这是一些入门问题:
经过使用多个CSS背景,咱们能够将一个背景做为叠加层,将另外一个背景做为实际图像。请参阅下面的CSS:
.hero { background-image: linear-gradient(rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.4)), var('landscape.jpg'); background-repeat: no-repeat; background-size: 100%, cover; }
虽然此解决方案有效,但可使用JavaScript动态更改背景图片。见下面:
<section class="hero" style="background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('landscape.jpg');"> <!-- Hero content --> </section>
我添加了一个内联的CSS背景。虽然这是可行的,但它看起来很丑,并且不实用。
也许咱们可使用CSS变量?让咱们来探索一下。
<section class="hero" style="--bg-url: url('landscape.jpg')"> <!-- Hero content --> </section>
如今,咱们能够轻松地更新 --bg-url
变量,这将动态更改背景。这比内联的CSS好一百万倍。
解决方案1要点:
对于此解决方案,咱们将使用HTML图像。见下面:
<section class="hero"> <h2 class="hero__title">Using Images in CSS</h2> <p class="hero__desc">An article about which and when to use</p> <img src="landscape.jpg" alt=""> </section>
在CSS中,咱们须要将图片绝对定位在内容下方,而且还须要使用伪元素做为叠加层。
.hero { position: relative; } .hero img { position: absolute; left: 0; top: 0; z-index: -1; width: 100%; height: 100%; object-fit: cover; } .hero:after { content: ""; position: absolute; left: 0; top: 0; z-index: -1; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.4); }
此解决方案的优势在于,能够轻松更改图片的 src
属性。一样,若是图像很重要,它将会更加有用。
另外,我喜欢使用HTML <img>
的地方是能够在图片没有加载的状况下添加一个回退方法,这个回退至少能够保持内容的可读性。
.hero img { /* 其余样式 */ background: #2962ff; }
好处是,只有在图像源失败的状况下,背景才会起做用。那不是很酷吗?
Logo是很重要的,由于它能够将网站与其余网站区分开。要嵌入Logo,咱们有两种选择:
<img>
--> png,jpg,或者 svg让咱们学习使用哪一种技术以及如何选择合适的技术。
当一个LOGO有不少细节或形状时,用内嵌式SVG可能没有那么多好处。我建议使用 <img>
,图片类型能够是png
、jpg
或 svg
。
<a href="#"><img src="logo.svg" alt="Nature Food"></a>
咱们有一个简单的Logo,其中包含形状和文字。悬停时,形状和文本须要更改颜色。怎么作?对我来讲最好的解决方案是使用内联SVG。
<a href="#"> <svg class="logo" width="115" height="47" xmlns="http://www.w3.org/2000/svg"> <g transform="translate(-5 -5)" fill="none" fill-rule="evenodd"> <rect fill="#D8D8D8" transform="rotate(45 28.5 28.5)" x="9" y="9" width="39" height="39" rx="11" /> <text font-family="Rubik-Medium, Rubik" font-size="25" font-weight="400" fill="#6F6F6F"> <tspan x="63.923" y="36.923">Rect</tspan> </text> </g> </svg> </a>
.logo rect, .logo text { transition: 0.3s ease-out; } .logo:hover rect, .logo:hover text { fill: #4a7def; }
这让我想起了Smashing Magazine的Logo,我喜欢它从一个小图标变成一个完整的Logo。参见下面的模型:
完美的解决方案是 <picture>
元素,能够在其中添加Logo的两个版本。见下文:
<a class="logo" href="/"> <picture> <source media="(min-width: 1350px)" srcset="sm-logo--full.svg"> <img src="sm-logo.svg" alt="Smashing Magazine"> </picture> </a>
在CSS中,咱们须要将视口的宽度更改成等于或大于 1350px
。
.logo { display: inline-block; width: 45px; } @media (min-width: 1350px) { .logo { width: 180px; } }
简单明了的解决方案。
当Logo具备渐变时,从Illustrator或Sketch等设计应用程序将其导出的过程可能并不完美,有时会中断。
使用SVG,咱们能够轻松地为徽标添加渐变,我添加了 <linearGradient>
并将其用做文本填充。
<svg class="logo" width="115" height="47" xmlns="http://www.w3.org/2000/svg"> <defs> <linearGradient id="gradient" x1="0%" y1="100%" x2="0%" y2="0%"> <stop offset="0%" stop-color="#4a7def"></stop> <stop offset="50%" stop-color="#ab4787"></stop> </linearGradient> </defs> <g transform="translate(-5 -5)" fill="none" fill-rule="evenodd"> <rect fill="#AB4787" transform="rotate(45 28.5 28.5)" x="9" y="9" width="39" height="39" rx="11" /> <text font-family="Rubik-Medium, Rubik" font-size="30" font-weight="400" fill="url(#gradient)"> <tspan x="63.923" y="36.923">Rect</tspan> </text> </g> </svg>
对于用户头像,它们有不少形状,但最多见的是矩形或圆形。在这个用例中,我颇有兴趣解释一个你可能会以为有用的重要技巧。
首先,咱们来看看下面的模拟图。注意,咱们有一个完美的头像,并且它们是100%的清晰。
可是,当用户上传半白色头像或很是浅的头像时,此设计将失败。
注意到上面的模拟图中,你要真的聚焦好了才知道里面有一个圆形。这就是一个问题,为了解决这个问题,咱们应该在头像内部添加一个边框,这将是在图像太亮的状况下做为备用。
咱们有两种选择能够作到这一点:
<img>
元素<div>
的 <img>
<div>
<image>
其中哪个最好?让咱们来探索。
<img>
您可能想到的第一件事就是添加边框,对吗?让咱们来探讨一下(很抱歉,在下面的部分中,您可能会看到不少个人脸)。
.avatar { border: 2px solid #f2f2f2; }
咱们的目标是要有一个与图像相融合的内部边框,具备实边是不实际的。
<div>
的 <img>
如今的问题是,要添加内边框,咱们不能使用内部 box-shadow
,由于它对图像不起做用。解决的方法是用 <div>
包裹头像,并添加一个专门用于内边框的元素。
<div class="avatar-wrapper"> <img class="avatar" src="shadeed2.jpg" alt="A photo of Ahmad Shadeed"> <div class="avatar-border"></div> </div>
.avatar-wrapper { position: relative; width: 150px; height: 150px; } .avatar-border { position: absolute; left: 0; top: 0; width: 100%; height: 100%; border-radius: 50%; border: 2px solid rgba(0, 0, 0, 0.1); }
经过在 <div>
上设置一个10%的黑色边框,咱们能够确保边框与暗色图像融合,只有在图像颜色较浅的状况下,边框才会显现出来。请看下面的模拟图。
<div>
若是我要使用 <div>
来显示头像,则可能表示该图像具备装饰性。我记得一个用例,它是分散在页面中的随机头像。
咱们能够有这样的东西:
<div class="avatar" style="--img-url: url(shadeed2.jpg)"></div>
.avatar { background: var(--img-url) center/cover; width: 150px; height: 150px; border-radius: 50%; box-shadow: inset 0 0 0 2px rgba(#000, 0.1); }
<image>
对我来讲,这是最有趣的解决方案。我在检查Facebook的新设计时注意到了它。
<svg role="none" style="height: 36px; width: 36px;"> <mask id="avatar"> <circle cx="18" cy="18" fill="white" r="18"></circle> </mask> <g mask="url(#avatar)"> <image x="0" y="0" height="100%" preserveAspectRatio="xMidYMid slice" width="100%" xlink:href="avatar.jpg" style="height: 36px; width: 36px;"></image> <circle cx="18" cy="18" r="18"></circle> </g> </svg>
我先对其进行剖析,它包含如下内容:
preserveAspectRatio = "xMidYMid"
在CSS中,咱们将具备如下内容:
circle { stroke-width: 2; stroke: rgba(0, 0, 0, 0.1); fill: none; }
这就是用户头像用例的所有内容。
一般会看到带有图标的输入框,如何添加?当输入被聚焦时会发生什么?让咱们来探索一下。
<p> <label for="name">Full name</label> <input type="text" id="name"> </p>
对我来讲,处理这种状况的最佳解决方案是CSS背景图片。简单,快捷,不须要添加更多元素。
input { background-color: #fff; background-image: url('user.svg'); background-size: 20px 20px; background-position: left 10px center; background-repeat: no-repeat; }
要更改焦点上的图标颜色,咱们可使用url编码的SVG,而且很容易作到这一点。Yoksel的这个工具很棒。
用户可能须要打印web页面。假设咱们有一份食谱,你想把它打印出来,这样你就能够在厨房里看它,而不须要查看你的手机或电脑。
对于包含说明性步骤的菜谱,重要的是将它们打印出来,不然用户将没法从打印web页面中得到任何好处。
当一个图像做为CSS背景被包含进来时,它不会被打印出来,取而代之的是一个空白区域。以下图所示:
就是这样的状况。咱们能够经过强制浏览器显示图片来解决这个问题,虽然这对Firefox和IE来讲不起做用。
.element { background: url('cheesecake.png') center/cover no-repeat; -webkit-print-color-adjust: exact; /* 强制浏览器以打印模式呈现背景 */ }
可是,使用HTML <img>
会更安全,由于它能够打印而不会出现任何问题。
全文完。
本文获原做者Ahmad Shadeed受权翻译
若是对你有所启发和帮助,能够点个关注、收藏、转发,也能够留言讨论,这是对做者的最大鼓励。
做者简介:Web前端工程师,全栈开发工程师、持续学习者。