前端開發人員在構建網站時須要作出的決定之一就是添加圖片的技術。它能夠是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前端工程師,全棧開發工程師、持續學習者。