I am three diamonds, one of you in “Technology Galaxy” to come together for a lifetime of drifting learning.

Praise is power, attention is recognition, comment is love! See you next time 👋!

We’ve taken a new look at selectors in the previous section of Learn How Browsers Work in Action. Let’s look at selectors from the perspective of CSS.

Selector syntax

Let’s take a look at the selector syntax and then dive into the underlying features.

Simple selector

  • The asterisk*
    • Universal selector that can select any element
  • Type selector| type selector –div svg|a
    • It’s also called a type selector, which means it selects one of the elementstagName(Tag name) property
    • TagName is also the most commonly used selector
    • But because HTML also has namespaces, it has three main ones:HTML,SVG,MathML
    • If we want to select a specific element in SVG or MathML, we must use a single vertical bar|In CSS selectors, the single bar is a namespace separator, whereas in HTML, the namespace separator is a colon:. However, this namespace is not used very often. It exists only for completeness. The only element name that overlaps in HTML and SVG is only onea
    • So we can think of a type selector as a simple text string
  • Class selector —.class-name
    • In order to.The first selector, the class selector, is one of the most classic
    • It will select one class, or we can specify multiple classes with Spaces as delimiters
    • this.classYou just have to match one of them
  • The ID selector| id selector –#id
    • In order to#Start with the ID name and select an ID
    • This is a strict match
    • ID can be plus or minus or whatever
  • Attribute selector | Attribute Selector —[attr=value]
    • It includes a class attribute selector and an ID selector
    • The full syntax of this selector isattr=valueIs equal to the property name followed by the property value
    • I can put an equal sign in front of it~Denotes a sequence of space-separated values that, like class, can be supported:attr~=value
    • If the equals sign is preceded by a single vertical line, the property begins with this value:attr|=value
    • If we have no special priority requirements, we could theoretically use attribute selectors instead of class and ID selectors
  • pseudo-classes:hover
    • In order to:At the beginning, it’s basically a special state of some property
    • This has nothing to do with the HTML we’re writing, it comes mostly from interactions and effects
    • Some pseudo-class selectors are pseudo-class selectors with functions, which we can use to solve the pseudo-class
  • Pseudo element selector::before
    • Generally speaking: :Double colon
    • We actually support single colons, but we advocate double colons
    • Because we can tell at a glance that this is a pseudo-element selector, distinguished from a pseudo-class
    • Pseudo-elements are elements that are selected that do not originally exist
    • If we don’t select them, there won’t be an element there, there will be one more element

Compound selector

  • < Simple selector >< Simple selector >
  • * or div must be written first

First, a compound selector is composed of multiple simple selectors. Simply write the simple selectors next to each other to make a compound selector. The semantics are that the selected element must match several simple selectors at the same time, forming an “and” relationship.

Complex selector

Compound selectors can be changed into complex selectors by using a concatenation in the middle, and complex selectors are selected for the structure of an element.

  • < compound selector > < compound selector > – descendant selector. A single element must have a parent or ancestor node to the left of the space
  • < compound selector >” >” < compound selector > – parent selector, must be the element’s immediate parent element
  • < compound selector > “~” < compound selector > — adjacency selector
  • < compound selector > “+” < compound selector > — adjacency selector
  • Compound Selector < > “| |” “< compound Selector > — double vertical bar is the Selector Level 4, when we do form can be selected to each column

Selector priority

I’ve also been exposed to the concept of selector priorities in learning How Browsers Work in The Field. Here we take a closer look at the concept of selector priority.

Simple selector count

Let’s start with an example where selector priority is a count of all simple selectors contained in a single selector. So the selector list is not considered a complete selector (i.e., a comma-separated selector), because the simple selector count is done with a comma-separated complex selector.

Example: #id div.a#id

  • This contains two ID selectors, a type selector and a class selector
  • According to aspecificityArray count [The inline - style number.ID Number of selectors.Number of class selectors.TagName Number of selectors]
  • That’s what we’re going to get in this casespecificity = [0, 2, 1, 1]
  • In the selector standard, there is a description that we will use an n-base to indicate the selector priority
  • Therefore, a full spectrum of various organs could be used for various studies of various organs. Therefore, a full spectrum =0∗N3+2∗N2+1∗N1+1Specificity =0 * N^3 +2 * N^2 +1 * N^1 +1Specificity =0∗N3+2∗N2+1∗N1+1
  • We just have to take a big enough N, and that’s the priority of the selector
  • Let’s say we use
    N = 1000000 N = 1000000
    , then
    S = 2000001000001 S = 2000001000001
    That’s the selector in this examplespecificityThe priority

For example, the old version of Internet Explorer, IE6, because N is not large enough to save memory, took a 255 value of N, so very interesting things happen, for example, to the value we have 256 classes is equivalent to an ID. Most of our browsers went to 65536 and we basically never went over the limit again. Because the standard only says to use a large value, but we need to consider the temporary memory problem, so we will take a hexadecimal integer, generally a power of 256 (because 256 is exactly one byte).

CSS pseudo-classes

Pseudo classes are actually simple selectors for a very large class of content.

Link/behavior

  • :any-linkCan match any hyperlink
  • :link— Hyperlinks that have not been visited
  • :link :visitedMatches all hyperlinks that have been visited
  • :hoverThe state of the user’s mouse pointer over an element, which previously only worked with hyperlinks, now works with many elements
  • :active– Previously, it only worked on hyperlinks, clicking on the current link will work
  • :focusThis is the state of the focus in this element. This is used for the input tag, but can be used for any element that can get focus
  • :targetLink to current destination, this is not for hyperlinks, this is for anchorsaTag uses the current HASH to refer to the current HASHaTag words will activatetargetpseudo-classes

Once you use: Link or :visited, you can no longer change attributes other than the text color of this element. Why is it designed this way? Because once we use layout-related attributes, for example, we increase the size of: Visited a little, it will affect the scheduling. This way we can use the JavaScript API to find out if the link has been accessed. But if we can see if the link has been visited, then we can know which sites the user has visited, which is a fatal blow to browser security. So here’s a reminder, don’t think that doing something expressive has nothing to do with safety, but safety is a comprehensive consideration. CSS can also cause security holes.

Tree structure

  • :empty— Whether this element has children
  • :nth-child()Is the child of the parent element
  • :nth-last-child()– andnth-childSame thing, just counting backwards
  • :first-child :last-child :only-child

Nth-child: nth-Child is a very complex pseudo-class that supports a syntax such as an odd event or odd in parentheses, 4N+1 or 3n-1, which will match the integer form, respectively. Because this is a more complex selector, we’re not going to write overly complicated expressions in it, but we’re going to use it to deal with odd and even, 1 more than 3, 1 more than 4, and so on.

Empty, nTH-last-Child, last-Child, and only-Child are the two selectors that break the timing of CSS calculations we discussed in Learning browser Principles in Implementation. We can imagine that when we start the tag calculation, we don’t know if it has any child tags. Empty is not particularly influential, but the relationship between last-Child is actually quite influential. So browsing has a special way of doing this, either the browser doesn’t do it very well, or the browser takes more performance to do it. So I suggest you try to avoid using these in large quantities.

The logical model

  • :not pseudo-classes – mainstream browsers only support sequences of simple selectors (compound selectors) and there is no way to write the syntax of complex selectors in them
  • : WHERE: HAS — Added these two very powerful logical pseudo-classes to CSS Level 4

It is not recommended that you write the selector too complex, we can often add a little more class to solve the problem. If our selector is written too complex, it somehow means that the HTML structure is not written properly. Not just for the sake of browser engineering, not just for the sake of performance, but for the sake of our own code structure, so we shouldn’t have overly complex selectors.

CSS pseudo-elements

There are four types

  • ::before
  • ::after
  • ::first-line
  • ::first-letter

::before and ::after insert a pseudo-element before and after the content of the element. Once the before and after attributes are applied, the declaration contains a property called content (normal elements cannot write content attributes). The Content property, like a real DOM element, can be boxed and used for subsequent typesetting and rendering. So we can give it attributes like border, background, and so on.

A pseudo-element adds a nonexistent element to the interface.

The ::first-line and ::first-letter mechanisms are different. These two things are already in Content. They pick “first line” and “first letter” as the name suggests. They’re not an element that doesn’t exist, but they enclose part of the text so that we can do something with it.

Before and after

In our concept, we can think of a selector with a before pseudo-element as adding an element to the content of the element it actually selects. We can simply add text content to it via its Content property. (Here we can also give pseudo-elements content: “empty.) So we can give before and after any display attributes, just as we would for different elements.

We often use this approach to add embellishments to the page in a way that doesn’t pollute the DOM tree but actually creates a visual effect when implementing widgets.

<div>
  <::before/>
  content content content content
  content content content content
  content content content content
  content content content content
  <::after/>
</div>
Copy the code

The first letter and the first – line

First-letter means we have an element enclosing the first letter of the content. We can arbitrarily declare different attributes of this first-letter, but we cannot change its content. We’ve all seen the effect of the first letter in the newspaper being bigger and then drifting away. In CSS we can use ::first-letter pseudo-element selector. Using this implementation is much more stable and elegant than using JavaScript.

<div><::first-letter>c</::first-letter>ontent content content content content content content content content content content  content content content content content</div>
Copy the code

First-line refers to the line after typesetting, actually has nothing to do with the first line in our source code. If our browsers render with different widths, first-line will end up enclosing a different number of elements in both environments. So we need to use this selector according to the needs of the situation, it is likely that the rendering effect on our development machine and the user’s machine is not the same!

<div>
  <::first-line>content content content content content</::first-line>
  content content content content
  content content content content
  content content content content
</div>
Copy the code

The two selectors have different available properties:

First-line available attributes

  • The font series
  • Color series
  • Background series
  • word-spacing
  • letter-spacing
  • text-decoration
  • text-transform
  • line-height

First-letter attributes are available

  • The font series
  • Color series
  • Background series
  • text-decoration
  • text-transform
  • letter-spacing
  • word-spacing
  • line-height
  • float
  • vertical-align
  • Box model series: Margin, padding, border

Little practice

Write a match function. It takes two arguments, the first a selector string property and the second an HTML element. This element you can assume is going to be in a DOM tree. Use the selectors and DOM elements to determine if the current element matches our selector. (You can’t use any of the built-in browser functions to determine if an element matches a selector using the DOM’s parent and children apis.) Here is an example of a call.

<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Match Example -- by three diamonds</title>
  </head>
  <body>
    <div>
      <b>
        <div class="class classA" id="id">content</div>
      </b>
    </div>
  </body>
  <script language="javascript">
    /** * matches selector */
    function matchSelectors(selector, element) {
      // Matches the current element first
      let tagSelector = selector.match(/^[\w]+/gm);
      let idSelectors = selector.match(/ (? <=#)([\w\d\-\_]+)/gm);
      let classSelectors = selector.match(/ (? < = \.) ([\w\d\-\_]+)/gm);

      / * * * implementation compound selector, implementation support Spaces Class selector * -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /
      // Check whether the tag name matches
      if(tagSelector ! = =null) {
        if(element.tagName.toLowerCase() ! == tagSelector[0]) return false;
      }
      // Check whether the id matches
      if(idSelectors ! = =null) {
        let attr = element.attributes['id'].value;
        if (attr) {
          for (let selector of idSelectors) {
            if (attr.split(' ').indexOf(selector) === -1) return false; }}}// Check whether the class matches
      if(classSelectors ! = =null) {
        let attr = element.attributes['class'].value;
        if (attr) {
          for (let selector of classSelectors) {
            if (attr.split(' ').indexOf(selector) === -1) return false; }}}return true;
    }

    /** * matches the element */
    function match(selector, element) {
      if(! selector || ! element.attributes)return false;

      let selectors = selector.split(' ').reverse();

      if(! matchSelectors(selectors[0], element)) return false;

      let curElement = element;
      let matched = 1;

      // Recursively look for parent element matches
      while(curElement.parentElement ! = =null && matched < selectors.length) {
        curElement = curElement.parentElement;
        if (matchSelectors(selectors[matched], curElement)) matched++;
      }

      // All selectors match successfully; otherwise, they fail
      if(matched ! == selectors.length)return false;

      return true;
    }

    let matchResult = match('div #id.class'.document.getElementById('id'));
    console.log('Match example by three ');
    console.log('matchResult', matchResult);
  </script>
</html>

Copy the code