[CSS] Một vài thuộc tính CSS

[CSS] Một vài thuộc tính CSS

02-01-2022

Ngoài những thuộc tính hay được sử dụng (display, font-size, color,...), có một số thuộc tính thỉnh thoảng mới sử dụng một lần. Đôi khi nhiều người không biết đến chúng nên dẫn tới solution CSS của các bạn sẽ phức tạp hơn. Dưới đây là một vài ghi chú/giải thích về một số thuộc tính đó.

background-origin

Chúng ta có box-sizing để thiết lập thuộc tính height/width của một phần tử tính từ border vào hay từ content vào.

Tương tự như border-box, chúng ta có thuộc tính background-origin để thiết lập vùng hiển thị của background-image.

Thuộc tính này có 3 giá trị là: border-box, padding-boxcontent-box tương ứng với vùng hiển thị như tên giá trị của chúng. Giá trị mặc định là padding-box.


<div class="container">
<div>border box</div>
<div>padding box</div>
<div>content box</div>
</div>


.container {
border: 2px solid green;
}
.container div {
border: 5px solid transparent;
padding: 5px;
margin-top: 16px;
background-image: linear-gradient(to right, red, yellow);
background-repeat: no-repeat;
background-color: blue;
}
div:nth-child(1) {
background-origin: border-box;
}
div:nth-child(2) {
background-origin: padding-box;
}
div:nth-child(3) {
background-origin: content-box;
}

border box
padding box
content box

Nếu giá trị của background-attachmentfixed thì giá trị của background-origin sẽ bị bỏ qua.

background-clip

Tương tự như background-origin, chúng ta có thêm background-clip nhưng áp dụng cho cả background-color (background-origin chỉ áp dụng cho background-image).

Tuy nhiên, nó chỉ hỗ trợ để clip background, tức là cắt gọt khu vực background hiển thị chứ không phải thiết lập như background-origin, nên không thể thay thế background-origin được.

(Nếu muốn sử dụng background-clip full chức năng với background-image, chúng ta nên set background-origin: border-box, như vậy vùng hiển thị của image sẽ full để chúng ta có thể clip)

background-position

Đây là một thuộc tính khá thông dụng. Tuy nhiên background-position với giá trị là % thì có phần hơi đặc biệt và cần note lại.


<div class="bg-percentage"></div>


.bg-percentage {
height: 300px;
background-image: linear-gradient(to right, red, yellow);
background-size: 50% 100%;
background-position: 25% 25%;
background-repeat: no-repeat;
border: 1px solid green;
}

Nếu theo logic thông thường, chúng ta có thể nghĩ rằng vị trí của background image sẽ cách top của phần tử 25% và cách left 25%. Nhưng như demo phía trên, nó không hoạt động như vậy.

Đầu tiên nó sẽ tìm một điểm của phần tử mà vị trí đúng như background position, như ví dụ ở trên là 25% theo trục dọc và 25% theo trục ngang.

Tiếp theo, nó cũng sẽ tìm một điểm trong chính background image đó với vị trí như vậy, 25% theo trục dọc và 25% theo trục ngang.

Cuối cùng, nó sẽ dịch chuyển background image để 2 điểm đó trùng nhau. Chúng ta có hình minh họa phía dưới.

Và chúng ta có 2 điểm 25% 25% của phần tử và background image của nó trùng nhau.

isolation

Thuộc tính này rất hữu dụng khi sử dụng kèm z-index. Nó sẽ tạo một lớp stacking context mới cho phần tử.

Dưới đây là ví dụ mình thường dùng nhất trong các project, đó là sử dụng img như background.


<div class="container">
<img src="/images/bg.jpeg" />
<h1>This is a title</h1>
</div>


.container {
position: relative;
height: 300px;
display: flex;
justify-content: center;
align-items: center;
background: red;
}
.container img {
position: absolute;
z-index: -1;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}

This is a title

Việc sử dụng z-index: -1 đã làm cho img nằm hẳn dưới nền của container. Trong khi điều chúng ta muốn là chỉ nằm dưới các phần tử khác trong container mà thôi. Việc này nguyên nhân tại vì container dù sử dụng position relative nhưng không tạo ra một stacking context mới. Cách thông thường nhất để tạo một stacking context đó là sử dụng z-index kèm với position.

Nhưng chúng ta ở đây không muốn set z-index cho container bằng một số nào cả, giữ nguyên cấp độ mặc định của nó. Lúc này, sử dụng isolation là một giải pháp.


.container {
position: relative;
height: 300px;
display: flex;
justify-content: center;
align-items: center;
background: red;
isolation: isolate;
}
.container img {
position: absolute;
z-index: -1;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}

This is a title

writing-mode

Thuộc tính này chắc là ít dùng, nhưng khi gặp một số giao diện thì nó sẽ khá hữu dụng.

Ví dụ chúng ta có giao diện dưới đây:

This is a title

Để chữ nằm dọc vậy thì cách nhiều người nghĩ tới nhất có lẽ là dùng transform rotate. Tuy nhiên, vì khi rotate từ chiều ngang sang chiều dọc thì diện tích nó chiếm vẫn là chiều ngang ban đầu, không chiếm không gian của chiều dọc, do đó nếu text dài hơn ảnh thì sẽ bị overflow.

Cách dễ thứ hai đó chính là dùng writing-mode.

Xem qua docs của nó thì sẽ có 3 giá trị:


.wm {
writing-mode: horizontal-tb;
writing-mode: vertical-lr;
writing-mode: vertical-rl;
}

Chúng ta sẽ phân tích từng giá trị.

Đầu tiên là horizontal-tb, đây là giá trị mặc định, nó sẽ hiển thị chữ theo chiều ngang, từ trái sang phải hay phải sang trái là tùy direction mình cài (mặc định là left to right).

Tiếp theo là vertical-lrvertical-rl, lúc này chữ sẽ được viết theo chiều dọc.

2 ví dụ minh họa phía dưới lần lượt sử dụng vertical-lr và vertical-rl.

This is a title

This is a title

Nhìn có vẻ không khác gì, nhưng để thấy được sự khác nhau, chúng ta cần viết dài lên để nó rơi thành nhiều cột.

This is a really
long title

This is a really
long title

Và chúng ta sẽ thấy được sự khác biệt của left to right và right to left.

display: contents

Đây là một loại display đặc biệt, khi mà nó sẽ làm cho container (nơi khai báo display: contents) sẽ coi như biến mất, chỉ còn các phần tử con bên trong được trải phẳng (flat) ra ngoài.

Vậy thuộc tính này có gì hữu dụng. Đó là đối với các trường hợp responsive, layout ở mobile với desktop khác nhau một cách rõ ràng.

Lấy ví dụ không mấy đẹp như dưới đây, ở desktop chúng ta sẽ có một layout như thế này:

Title

Lorem ipsum dolor sit amet consectetur adipisicing elit. Inventore, ratione?Lorem ipsum dolor sit amet consectetur adipisicing elit. Inventore, ratione?Lorem ipsum dolor sit amet consectetur adipisicing elit. Inventore, ratione?

Về mobile chúng ta có như này:

Title

Lorem ipsum dolor sit amet consectetur adipisicing elit. Inventore, ratione?Lorem ipsum dolor sit amet consectetur adipisicing elit. Inventore, ratione?Lorem ipsum dolor sit amet consectetur adipisicing elit. Inventore, ratione?

Nếu "may mắn" bạn sẽ gặp phải design như thế này. Bởi vì khu vực text ở desktop có background, nên html, css tối thiểu sẽ phải như thế này.


<div class="container">
<img src="..." />
<div class="content">
<h2>Title</h2>
<p>Lorem....</p>
</div>
</div>


.container {
display: flex;
/* ... */
}
.content {
background: purple;
/* ... */
}

Vậy khi về mobile làm sao đưa h2 lên trên ảnh được, khi mà nó đang nằm trong content? Lúc này chúng ta sẽ áp dụng được display: contents.


/* ... */
@media (max-width: 768px) {
.container {
display: flex;
flex-direction: column;
/* ... */
}
.content {
background: purple;
display: contents;
/* ... */
}
.content h2 {
order: -1;
}
}

Title

Lorem ipsum dolor sit amet consectetur adipisicing elit. Inventore, ratione?Lorem ipsum dolor sit amet consectetur adipisicing elit. Inventore, ratione?Lorem ipsum dolor sit amet consectetur adipisicing elit. Inventore, ratione?

all

Thuộc tính này cũng khá hay ho. Khi mình sử dụng những generator để viết blog như này, thì rất nhiều style đã được định dạng sẵn. Ví dụ như table, nhiều lúc mình viết tutorial để hướng dẫn css với table, nhưng table hiện ra UI đã bị chỉnh sửa style, mình phải đè style lại cho từng thuộc tính rất mệt.

Lúc này, nhu cầu của mình là reset tất cả các thuộc tính về giá trị ban đầu của nó, lúc chưa có bất style nào.

Và thuộc tính all sẽ giúp mình được chuyện đó.


table {
all: unset;
}

Ngoài ra, all còn có những giá trị có thể khác nữa là: initial, inheritrevert.

Chúng ta sẽ thảo luận chi tiết ý nghĩa các giá trị đó trong mục bên dưới.

initial, inherit, unset, revert

Đây không phải thuộc tính, mà là giá trị mà có lẽ tất cả các thuộc tính css đều có, vậy chúng có nghĩa là gì?

  • initial: Đây là một giá trị ám chỉ giá trị mặc định của một thuộc tính. Ví dụ, font-weight sẽ có giá trị mặc định là normal, tức là 400. Khi chúng ta sử dụng font-weight: initial nó sẽ tương đương với font-weight: normal.

Bảng các giá trị mặc định của các thuộc tính được liệt kê ở đây: Link

  • inherit: Dịch ra có nghĩa là kế thừa, tức là thuộc tính nào sử dụng giá trị này sẽ có kết quả là giá trị như các phần tử bọc bên ngoài nó. Trở lại thuộc tính font-weight, là một thuộc tính có tính chất kế thừa, mặc định nó sẽ không mang giá trị initial mà sẽ là inherit, kế thừa giá trị từ các phần tử bọc bên ngoài nó. Tất nhiên, nếu chúng ta muốn nó mang giá trị mặc định, chúng ta có thể set font-weight: initial như ở trên.

Tuy các thuộc tính thuộc loại kế thừa, giá trị nó thể hiện sẽ là inherit, nhưng nếu là thẻ html, tức là root, nó không thể kế thừa vì nó là phần tử ngoài cùng. Lúc này, các thuộc tính (thuộc loại inherit) dành cho html sẽ mang giá trị initial.

  • unset: Khi sử dụng giá trị này, nó sẽ set lại giá trị của thuộc tính là inherit nếu thuộc tính đó thuộc loại kế thừa, còn không sẽ là initial. Tức là nó sẽ reset về initial hoặc inherit tùy loại thuộc tính.

.a {
font-weight: unset;
/*tương đương với*/
font-weight: inherit;
}
.b {
display: unset;
/*tương đương với*/
display: initial;
}

  • revert: Đây là một giá trị đặc biệt, tương tự như unset. Tuy nhiên, thay vì chuyển thành initial hay inherit, nó sẽ chuyển về giá trị mặc định mà trình duyệt đã quy định cho thuộc tính đó.

Ví dụ, nếu chúng ta reset giá trị display dành cho table sử dụng revert:


table {
display: revert;
}

display không phải thuộc tính dạng kế thừa, nên nếu dùng unset, chúng ta sẽ set nó về initial, cụ thể là inline. Nhưng vì dùng revert, nó sẽ reset về giá trị mà trình duyệt quy định cho nó:


table {
display: revert;
}
/* Tương đương với */
table {
display: table;
}

overscroll-behavior

Ở dưới mình có một box màu xanh và một box màu vàng, box xanh bọc box vàng. Và 2 box hiện có content dài hơn chiều cao của box, nên bạn có thể sử dụng chuột để scroll trong box vàng hay box xanh.

Nếu bạn thử scroll trong box vàng, đến đáy của box vàng, nó sẽ tự động tiếp tục scroll box xanh.

Something goodBlue box bottom
Something differentYellow box bottom

Vậy, nếu chúng ta muốn scroll trong box vàng, đến đáy thì dừng lại, dù scroll tiếp (chuột đang ở trong box vàng) thì không làm cho box xanh scroll phải làm sao?


.yellow-box {
overscroll-behavior: contain;
}

Như vậy, chúng ta sẽ chặn được việc scroll tiếp tục dù chạm đáy box vàng.

Something goodBlue box bottom
Something differentYellow box bottom

overscroll-behavior còn có một giá trị nữa là none. Nó tương tự như contain, nhưng disable thêm hiệu ứng khác nữa.

Cụ thể, à mà bạn có thể tự đọc ở đây để có video minh họa: Link.