Theme NexT works best with JavaScript enabled

ShunNien's Blog

不積跬步,無以致千里;不積小流,無以成江海。

0%

CSS Grid 筆記 20-CSS Grid Image Gallery

demo

結合前幾篇,使用 jscss 完成表格布置的排版,應用巢狀表格 完成圖片隨機大小的表格呈現

Demo | Github

CSS Grid Image Gallery

此練習初始 html 如下:

1
2
3
4
5
6
7
8
9
<div class="overlay">
<div class="overlay-inner">
<button class="close">× Close</button>
<img>
</div>
</div>

<section class="gallery">
</section>

接著撰寫 javascript ,以下 js 連帶說明一起附上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// 宣告 gallery 取得 .gallery element
const gallery = document.querySelector('.gallery');
// 宣告 overlay 取得 .overlay element
const overlay = document.querySelector('.overlay');
// 宣告 overlayImage 取得 img element
const overlayImage = overlay.querySelector('img');
// 宣告 overlayClose 取得 .close element
const overlayClose = overlay.querySelector('.close');

/**
* 產生圖片畫廊的 html
* h 是 grid-column 跨越 column 數量
* v 是 grid-row 跨越 row 數量
* @param {any} [h, v] [grid-column grid-row]
* @returns html 字串
*/
function generateHTML([h, v]) {
// 圖片採用隨機選擇 images/${randomNumber(12)}.jpg
return `
<div class="item h${h} v${v}">
<img src="images/${randomNumber(12)}.jpg">
<div class="item__overlay">
<button>View →</button>
</div>
</div>
`;
}

/**
* 隨機數字
* @param {any} limit 範圍大小
* @returns 隨機數字
*/
function randomNumber(limit) {
return Math.floor(Math.random() * limit) + 1;
}

/**
* 按下 VIEW-> 觸發事件
* 開啟原始圖片大小的畫面
* @param {any} e
*/
function handleClick(e) {
// 取得點選 grid 圖片的路徑
const src = e.currentTarget.querySelector('img').src;
// 設定呈現原始圖片大小的 html tag 路徑
overlayImage.src = src;
// 設定 css 顯示
overlay.classList.add('open');
}

/**
* 關閉原始圖片大小的畫面
*/
function close() {
overlay.classList.remove('open');
}

// 產生一組長度 50 的巢狀 array
// 每一元素都是 array [隨機數字, 隨機數字]
// 隨機數字最大值為 4 ,最小值為 1
// 另外合併幾組 array [1,1]
const digits = Array.from({length: 50}, () => [randomNumber(4), randomNumber(4)]).concat([
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1]
]);

// 利用 digits 的陣列,產生圖片 html
const html = digits.map(generateHTML).join('');
// 將產生的 html 寫入到畫面
gallery.innerHTML = html;

// 取得所有 .item 的元素
const items = document.querySelectorAll('.item');

// 進行觸發事件的綁定
items.forEach(item => item.addEventListener('click', handleClick));

// 關閉畫面的事件綁定
overlayClose.addEventListener('click', close);

設定完成 javascript ,就可以來處理 css 了,針對 .gallery 讓圖片畫面集中,所以使用 grid-auto-flow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
* {
box-sizing: border-box;
}

body {
padding: 50px;
font-family: sans-serif;
background: linear-gradient(to right, #F93D66, #6D47D9);
}

h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0 0 5px 0;
}

p {
margin: 0 0 20px 0;
}

/* 關閉按鈕樣式 */
.close {
background: none;
color: black;
border: 0;
}

.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
grid-auto-rows: 100px;
/* 讓 grid 集中 */
grid-auto-flow: dense;
}


.item {
overflow: hidden;
display: grid;
grid-template-columns: 1;
grid-template-rows: 1;
}

.item img {
grid-column: 1/-1;
grid-row: 1/-1;
width: 100%;
height: 100%;
/* 圖片填滿畫面 */
object-fit: cover;
}

.item__overlay {
/* 背景顏色除了顏色加上透明度 rrggbbaa */
background: #ffc60032;
grid-column: 1/ -1;
grid-row: 1/-1;
position: relative;
display: grid;
/* 排版置中 */
justify-items: center;
align-items: center;
transition: 0.2s;
/* 將按鈕先隱藏 */
transform: translateY(100%);
}

.item__overlay button {
background: none;
border: 2px solid white;
color: white;
text-transform: uppercase;
background: rgba(0, 0, 0, 0.7);
padding: 5px;
}

.item:hover .item__overlay {
/* 讓隱藏按鈕出現 */
transform: translateY(0);
}

.item.v2 {
grid-row: span 2;
}

.item.v3 {
grid-row: span 3;
}

.item.v4 {
grid-row: span 4;
}

.item.h2 {
grid-column: span 2;
}

.item.h3 {
grid-column: span 3;
}

.item.h4 {
grid-column: span 4;
}

.overlay {
position: fixed;
background: rgba(0, 0, 0, 0.7);
top: 0;
right: 0;
bottom: 0;
left: 0;
display: none;
z-index: 2;
}

.overlay.open {
display: grid;
align-items: center;
justify-items: center;
}

.overlay-inner {
background: white;
width: 700px;
padding: 20px;
}

.overlay img {
width: 100%;
}

線上展示

筆記與備註事項

object-fit

首先來看一下 MDN 上的定義

The object-fit CSS property specifies how the contents of a replaced element should be fitted to the box established by its used height and width.
資料來源 - MDN

此段說明了 object-fit 主要是設定 replaced element (置換元素),置換元素的定義,請參考以下

CSS 中所謂的「置換元素 (Replaced element)」,即是該元素所呈現的內容不在 CSS 的控制範圍之內。這類外部物件所呈現的內容均獨立於 CSS 之外。常見的置換元素包含 <img>、<object>、<video>,或如 <textarea> 與 <input> 的表單元素。某些元素 (像是 <audio> 或 <canvas>) 只有在特殊情況下才是置替換元素。若是透過 CSS content 屬性所插入的物件,則稱為「不具名置換元素 (Anonymous replaced elements)」。
資料來源 - MDN

object-fit 的設定屬性有以下,其定義說明如下:

  • fill:預設值,會填滿設定的容器大小,不管原檔比例
  • contain:保持原檔比例,並縮放至可以放進容器的大小。所以,容器內可能會有空白的地方
  • cover:保持原檔比例,替換內容大於容器尺寸。因此,部分內容可能會被遮蔽
  • none:保持原檔大小,不做任何調整
  • scale-down:會選擇 nonecontain 兩者間呈現較小尺寸的那個設定

參考資料

歡迎關注我的其它發布渠道