最新一段時間比較喜歡玩弄圖表,出於好奇,我想找出比較好的用 CSS 製作圖表的方案。開始學習網上開源圖表庫,它對我學習新的和不熟悉的前端技術很有幫助,比如這個:CSS Grid。
今天和大家分享我學到的新知識:如何用 CSS Grid 佈局製作一個普通的響應式柱狀圖。先上效果圖:
這篇文章的示例只是一個試驗,用來學習 CSS Grid 佈局,加上本人也是現學現賣,所以本文出現的程式碼不具有太多的參照意義。
第一個簡單版本
第一眼看上去可能會有點不知道怎麼開始,因此我們先來關注如何建立一個簡單的版本。首先,我們需要為圖表編寫 HTML 標籤:
<div class="chart">
<div class="bar-1"></div>
<div class="bar-2"></div>
<div class="bar-3"></div>
<div class="bar-4"></div>
<!-- 一直到 bar-12 -->
</div>
這些 bar-
開頭的 div 標籤將對應柱狀圖中的一條柱子,整篇文章所需要的 HTML 就這麼多。
現在按照我的步驟和簡單的解說一步一步用 CSS 把柱狀圖大概的樣式畫出來,不用過多地擔心下面出現的可能對你有些陌生的 CSS 語義,稍後我們將重點介紹關於 CSS Grid 的知識。
好了,現在開始我們的 CSS 樣式編寫。我們先對父元素新增一些必要的樣式:
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
background-color: #eee;
display: flex;
justify-content: center;
}
.chart {
height: 100vh;
width: 70vw;
}
我們需要在圖表中有 12 個條形,中間有 5px 的間距,按此需求,我們可以對父類 .chart
編寫如下 Grid 相關的樣式:
.chart {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: repeat(100, 1fr);
grid-column-gap: 5px;
}
對於熟悉 Grid 佈局的人來說,這是非常簡單的。上面程式碼表達的是:“我想要 12 列,每個子元素具有相同的寬度(1fr = 1 fraction),高度分為 100 等分,1 等分為一行(這樣方便計算),它們之間有 5px 的間隔。”
到這裡,我們的圖表仍然是空的,因為我們沒有告訴我們的子元素如何去佔用網格中的空間。我們使用 grid-row-start
和 grid-row-end
屬性來填充網格中的垂直空間,後而我們將通過改變這兩個屬性來定義各個子元素自己的高度。為樣式類為 bar
開頭子元素新增如下樣:
[class*='bar'] {
grid-row-start: 1;
grid-row-end: 101;
border-radius: 5px 5px 0 0;
background-color: #ff4136;
}
現在可以得到這樣的效果:
我們告訴每個柱狀圖從網格的頂部(1)開始,然後在底部(101)結束。上面我們把網格劃分了 100 行,為什麼要使用 101 作為該屬性的值呢?如果你被這些 Grid 屬性搞蒙了,沒關係!在我們繼續之前,讓我們對此進行一點探討。
理解網格線
Grid 佈局的一個特殊之處就是網格線的概念,這對理解這個新的佈局工具非常重要。以下是網格線在四行四列網格中繪製的示意圖:
這四行四列的對應的樣式是這樣的(特殊的黑色區域對應的樣式類為 special-col
):
.grid {
grid-gap: 5px;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(4, 1fr);
}
.special-col {
grid-row: 2 / 4;
background-color: #333;
}
grid-row
是 grid-row-start
和 grid-row-end
的簡寫屬性,前者表示元素在網格中的開始位置,後者表示元素在網格中的結束位置。注意到沒,黑色塊是從第 2 條網格線開始的,並在第 4 條網格線結束(而不是在第 4 行)。如果我們想讓那個黑盒子填滿所有 4 行,那麼我們需要在第 5 條網格線結束,即:1 / 5。理解這一點很重要。
換句話說,我們不應該認為子元素在一個網格中佔據整個行或列,而應該只跨越這些網格線的。我花了不少時間才從概念上理解並習慣了這一點,因為我最近深入研究了 Jen Simmons 關於這個問題的教程。
回到示例
這就是為什麼在我們上面的圖表示例中,所有列都在 101 這個值結束,因為 101 代表的是第 101 條網路線,而不是第 100 行。
現在,由於我們的 .chart
使用了 vw/vh 單位,也就有了一個響應良好的圖表,不需要再做其它的額外工作來支援響應式。如果你調整瀏覽器大小,你會發現它可以很好地壓縮或延伸,它總是佔據整個視窗。
理解了網路線的概念,我們就可以很輕鬆地為柱子調整高度了,我們需要讓各柱子高度參差不一。
.bar-1 {
grid-row-start: 55;
}
.bar-2 {
grid-row-start: 1;
}
...(略);
最後我們使寄偶數的柱子顏色不一樣:
[class*='bar']:nth-child(odd) {
background-color: #ff4136;
}
[class*='bar']:nth-child(even) {
background-color: #0074d9;
}
效果:
我們就這樣製作完成了一個支援響應式的柱狀圖。當然,這個示例只是一個開始,距離要達到實際應用的效果還有很多事情要做。比如畫標註和軸、通過 JS 來繫結真實的業務資料等。