You may know how to solve this problem, but do you really understand the reason behind it?

Stone tablets

Take a look at the following sample code that uses display under the ul element: inline-block; Horizontally arranged li elements.


      
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSS Demo</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        #root {
            width: 400px;
            border: 3px solid #7abdb6;
            margin: 40px;
            padding: 20px;
        }
        ul > li {
            display: inline-block;
            padding: 5px;
            background: #27a3ff;
            color: aliceblue;
        }
    </style>
</head>
<body>
<div id="root">
    <ul>
        <li>A</li>
        <li>B</li>
        <li>C</li>
    </ul>
</div>
</body>
</html>
Copy the code

line

Excuse me, whyliThere are gaps between the elements, right?

By using document.queryselector (‘ul’).childnodes to retrieve the childNodes of the ul element, you can find that there is a text node of type 3 between the li elements called text. The gap is the space occupied by the text node.

How do you get rid of it?liWhat about the Spaces between the elements?

Delete the text node. For example, we can write it like this:

<div id="root">
    <ul><li>A</li><li>B</li><li>C</li></ul>
</div>
Copy the code

Good, but that makes the code less readable. Is there a more elegant way?

Whitespace text nodes can be automatically removed using an HTML parser. For example, in a VUE project, we could write:

<div id="root">
    <div id="app"></div>
</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script>
    (function () {
        const res = Vue.compile(` 
       
  • A
  • B
  • C
`
, { whitespace: 'condense' }); new Vue({ el: '#app'.render: res.render, staticRenderFns: res.staticRenderFns, }); } ());
</script> Copy the code

Is there a way not to delete whitespace characters?

Font-size: 0; , so that whitespace characters do not take up space, for example:

ul {
    font-size: 0;
}

li {
    font-size: initial;
}
Copy the code

Although Chrome only allows a minimum size of 12px by default, 0px is also allowed.

What other solutions are there from a layout point of view?

Yes, you can use a floating layout, for example:

ul:after {
    content: ' ';
    display: block;
    clear: both;
    height: 0;
    visibility: hidden;
}

li {
    float: left;
}
Copy the code

Or use an elastic box layout:

ul {
    display: flex;
}
Copy the code

Then why usefloatorflexAfter that,liThe space between the characters doesn’t take up space?

Let’s switch to a simpler example:

<p>
    <span>A</span>
    <span>B</span>
</p>
<p>
    <span>C</span><span>D</span>
</p>
Copy the code

You can see that after the browser renders, there is A gap between A and B, while C and D are next to each other.

Let’s take a look at human language.

In Chinese (and some other languages as well), words are directly related to each other.

JavaScript is the best language in the world.

But in English (and some other languages as well), words are separated by Spaces.

JavaScript is the best language in the world.

Therefore, when browsers render inline elements, including text, they must preserve render whitespace characters to ensure semantic correctness.

That is, there is a gap between li, essentially because display: inline-block; Convert them to inline elements. So browsers render them using the same strategy as text rendering, treating each li as a single word so that the Spaces between them remain rendered. Using float means using a block layout, which modifies the calculated value of the display property in some cases. So li’s display property, while ostensibly inline-block, has actually been changed to block. The same is true for Flex.

Going back to the beginning,ulThere are 7 children below. Why don’t the first and last text nodes take up space?

console.log(document.querySelector('ul > li:first-child').getBoundingClientRect());

// DOMRect {x: 63, y: 63, width: 30.515625, height: 32, top: 63, right: 93.515625, bottom: 95, left: 63}
Copy the code

As you can see, the x of the first li element is 63, which is exactly equal to margin 40px + border 3px + padding 20px.

Also use a simpler example:

<div>
    Here is an English paragraph
    that is broken into multiple lines
    in the source code so that it can
    more easily read in a text editor.
</div>
Copy the code

You can see that this large chunk of text is rendered on the same line.

Back in the early days of the Internet, the web was purely static, so its content was hardcoded directly, not dynamically rendered or statically compiled like most of us do today. As a result, Spaces, indents, line feeds, and other whitespace characters are heavily used for readability and maintainability of HTML source code. But browsers can’t render all of this, so there’s a concept of folding successive whitespace characters.

In short, you fold successive whitespace characters into a single whitespace character and try not to render whitespace characters.

Here is a direct quote from the CSS specification.

At points 1, 3, and 4, successive foldable whitespace characters at the beginning and end of the line are removed during rendering, and if there are still foldable whitespace characters at the end of the line, they are suspended to the beginning of the line.

So, you can see that the first text node is not selected, but the seventh text node is selected and appears before the first Li!

Note: Here the seventh text node can be selected and has a width of 0, which is affected by the fifth text node.

If it were written as follows:

<ul>
    <li>A</li><li>B</li><li>C</li>
</ul>
Copy the code

The last text node also cannot be selected.

In actual combat

Some cosmic company interviewer sent a link to the source code on Codepen.

Excuse me, whydivThere are gaps between the elements, right?

I don’t remember.

End of question.

The map

  • Fighting the Space Between Inline Block Elements
  • White Space Processing Details
  • When does white space matter in HTML?
  • Whitespace in the DOM
  • Node.nodeType
  • Vue.compile(template)
  • compiler.compile(template, [options])
  • float
  • Line breaks
  • White space