CSS Selectors: Mọi thứ bạn cần biết về Combinator

Cập nhật: Lượt xem: 661 [ Css ]

Quy luật CSS được liên kết với các thành phần trên trang thông qua selectors. Bước liên kết này có rất nhiều cách thực hiện. Các selector thường thấy như element type, class name, ID, và attribute hiện đều được hỗ trợ mạnh mẽ và sử dụng rộng rãi.

CSS Selectors: Mọi thứ bạn cần biết về Combinator

Các tài liệu cho selectors cấp 3cấp 4 cũng có giới thiệu một vài selector mới. Trong một số trường hợp,  Đây là các biến thể mới của các kiểu selector đã có. Trong các trường hợp khác, chúng trở thành tính năng mới của ngôn ngữ.

Hôm nay, Chúng ta sẽ tìm hiểu môi trường trình duyệt hiện nay có ý nghĩa như thế nào với CSS selector, đặc biệt là các selector mới: attribute selector/combinator, cùng một loạt pseudo-class mới. Trong loạt bài viết này, chúng ta sẽ chỉ tập trung vào các selector có hỗ trợ tốt trình duyệt, và có tác dụng đáng kể cho công việc.

Combinators

Combinator (tổ hợp) là chuỗi ký tự thể hiện mối quan hệ giữa các selector được kết hợp. Khi sử dụng combinator, ta có được sản phẩm có tên gọi là selector phức hợp. Selector phức hợp có thể, trong một số trường hợp, là cách xác định style ngắn gọn nhất.

Bạn hẳn đã rất quen thuộc với các combinator sau:

  • Descendant combinator (tổ hợp thừa hưởng), hoặc ký tự khoảng trắng
  • Child combinator (tổ hợp con), hoặc >
  • Adjacent sibling combinator (tổ hợp anh chị em kề sát), hoặc +
  • general sibling combinator (tổ hợp anh chị em chung chung), hoặc ~

Hãy xem ví dụ cụ thể cho từng combinator này. Chúng ta sẽ dùng chúng để thêm style và HTML form dưới đây.

1482507332selectorscombinators-1024x796

Form này được cấu thành từ đống HTML sau:

<form method="GET" action="/processor">
<h1>Buy Tickets to the Web Developer Gala</h1>
<p>Tickets are $10 each. Dinner packages are an extra $5. All fields are required.</p>
<fieldset>
<legend>Tickets and Add-ons</legend>

<p>
<label for="quantity">Number of Tickets</label> 
<span class="help">Limit 8</span>
<input type="number" value="1" name="quantity" id="quantity" step="1" min="1" max="8">
</p>

<p>
<label for="quantity">Dinner Packages</label> 
<span class="help">Serves 2</span>
<input type="number" value="1" name="quantity" id="quantity" step="1" min="1" max="8">
</p>

</fieldset>
<fieldset>
<legend>Payment</legend>
<p>
<label for="ccn">Credit card number</label>
<span class="help">No spaces or dashes, please.</span>
<input type="text" id="ccn" name="ccn" placeholder="372000000000008" maxlength="16" size="16">
</p>
<p>
<label for="expiration">Expiration date</label>
<span class="help"><abbr title="Two-digit month">MM</abbr>/<abbr title="Four-digit Year">MM</abbr>YYYY</span>
<input type="text" id="expiration" name="expiration" placeholder="01/2018" maxlength="7" size="7">
</p>

</fieldset>
<fieldset>
<legend>Billing Address</legend>
<p>
<label for="name">Name</label>
<input type="text" id="name" name="name" placeholder="ex: John Q. Public" size="40"> 
</p>
<p>
<label for="street_address">Street Address</label>
<input type="text" id="name" name="name" placeholder="ex: 12345 Main Street, Apt 23" size="40">
</p>

<p>
<label for="city">City</label>
<input type="text" id="city" name="city" placeholder="ex: Anytown">
</p>

<p>
<label for="state">State</label>
<input type="text" id="state" name="state" placeholder="CA" maxlength="2" pattern="[A-W]{2}" size="2">
</p>

<p>
<label for="zip">ZIP</label>
<input type="text" id="zip" name="zip" placeholder="12345" maxlength="5" pattern="0-9{5}" size="5">
</p>
</fieldset>

<button type="submit">Buy Tickets!</button>
</form>

The Descendant Combinator

Chắc hẳn bạn không lạ gì descendant combinator. Descendant combinator đã có mặt ngay từ những ngày CSS mới xuất hiện (nhưng mà mãi đến CSS2.1 nó mới có tên). Combinator này được sử dụng và hỗ trợ vô cùng rộng rãi.

Descendant combinator chỉ là một ký tự khoảng trắng duy nhất. Nó giúp phân tách selector mẹ (cha) khỏi các selector hậu duệ, đi theo công thức A B, trong đó B là element chứa trong A. Hãy thử thêm CSS vào markup trên và xem thử ta có gì:

form h1 {
color: #009;
}

Chúng ta vừa mới thay đổi màu sắc của tiêu đề form, kết quả như sau:

descendantcombinator

Ta hãy thêm một ít CSS nữa, lần này là để tăng kích thước của đoạn message báo giá (“Tickets are $10 each”):

form p {
    font-size: 22px;
}

Tuy nhiên, selector này có xuất hiện vấn đề như bạn thấy bên dưới. Chúng ta đã vô tình gia tăng kích thước của tất cả cả đoạn text trong form (hoàn toàn không phải điều ta muốn). Giải quyết thế nào đây? Hãy thử dùng child combinator.

descendantcombinator2

The Child Combinator

Trái với descendant combinator, child combinator (>) chỉ lựa chọn các con trực tiếp của một element. Nó đi theo công thức A > B, khớp bất cứ element B nào tại nơi A là tổ tiên trược tiếp.

Nếu so sánh element với người, child combinator sẽ khớp với con của element mẹ. Nhưng descendant combinator chũng khớp cháu, và chắt của element mẹ đó. Hãy thử thay đổi selector trước đó để sử dụng child combinator.

form > p {
    font-size: 22px;
}

Giờ đây chỉ có con trực tiếp của article bị ảnh hưởng, như bên dưới.

descendantcombinator3

The Adjacent Sibling Combinator

Với adjacent sibling combinator (+), chúng ta có thể chỉ định các element theo nhau và có cùng bố mẹ. Nó đi theo công thức A + B. Styles sẽ được áp dụng vào element B mà có element A đứng ngay trước.

Hãy quay lại ví dụ của chúng ta. Bạn có để ý thấy label và input của chúng ta nằm cạnh nhau không? Như vậy có nghĩa rằng chúng ta có thể sử dụng adjacent sibling combinator để buộc chúng nằm ở những dòng khác nhau:

label + input {
    display: block;
    clear: both;
}

Kết quả như dưới đây:

descendantcombinator4

Hãy xét đến một ví dụ khác, kết hợp universal selector (*) với type selector:

* + fieldset {
    margin: 5em 0;
}

Ví dụ này thêm mép 5em vào phần đầu và đáy của mỗi element fieldset, như dưới đây. Vì ta đang sử dụng universal selector, Nên không cần phải lo lắng rằng liệu element trước đó có phải là element fieldset hay p hay không.

descendantcombinator5

Vậy nếu chúng ta muốn style một sibling element mà không kề sát với sibling element khác thì sao, chẳng hạn như trường Number of Tickets? Trường hợp này, chúng ta có thể sử dụng general sibling combinator.

The General Sibling Combinator

Với general sibling combinator (dấu ngã), chúng ta có thể select các element chùng chung một bố/mẹ mà không cần xem thử chúng có kề sát hay không. Giả sử ta có A ~ B, selector này khớp tất cả element B theo sau một element A, không cần biết có kề sát hay không.

một lần nữa, hãy xét đến trường Number of Tickets. Bạn sẽ có markup như sau:

<p>
    <label for="quantity">Number of Tickets</label> 
    <span class="help">Limit 8</span>
    <input type="number" value="1" name="quantity" id="quantity" step="1" min="1" max="8">
</p>

Element input của chúng ta đi theo element label, nhưng lại có element span nằm giữa. Vì element span nằm giữa inputlabel, adjacent sibling combinator sẽ không thể áp dụng vào đây. Hãy thay đổi adjacent sibling combinator thành general sibling combinator:

label ~ input {
    display: block;
}

Giờ thì tất cả element input đều nằm ở một dòng khác với element label, như dưới đây.

descendantcombinator6

Khi bạn thiếu khả năng kiểm soát markup, general sibling combinator sẽ cho thấy sức mạnh đáng sợ của mình. Nếu không, bạn chỉ việc điều chỉnh lại markup của mình để thêm class name là đủ. Nên nhớ rằng general sibling combinator có gây một số tác dụng phụ không mong muốn với các code base lớn, nên bạn cần cẩn thận một tí.

Theo: Sitepoint