Search code examples
htmlcssbrowserwhitespaceremoving-whitespace

Why is leading whitespace in a q element treated differently from other inline elements?


It seems that leading whitespace inside a <q> element is always preserved (albeit normalized to a single space), while this isn't the case for most inline elements. For example, the following code (jsFiddle):

<br> a <q>test</q> b <a href=#>test</a> c
<br> a <q>  test</q> b <a href=#>  test</a> c
<br> a <q>test  </q> b <a href=#>test  </a> c
<br> a <q>  test  </q> b <a href=#>  test  </a> c

Renders like this in all modern browsers I've tested (Chrome, FF, and Edge):

inconsistent spacing around q element

In the second and fourth line, the <q> is rendered with initial whitespace, while the <a> is not. Why is this?

EDIT: Adding the following CSS to the fiddle above:

a::before, a::after {
   content: '"';
}

Makes them render identically. So it seems to have something to do with the CSS ::before selector.


Solution

  • According to Chrome's docs on default styles for HTML elements, the default style for the <q> element (quote) is:

    q::before {
        content: open-quote;
    }
    
    q::after {
        content: close-quote;
    }
    

    As you noticed, if you apply the same style to the <a> element (anchor), you get the same results:

    body {
      font-size: 200%;
    }
    
    q {
      background-color: #AAF;
    }
    
    a {
      background-color: #FAA;
    }
    a::before {
      content: open-quote;
    }
    
    a::after {
      content: close-quote;
    }
    <br> a <q>test</q> b <a href=#>test</a> c
    <br> a <q>  test</q> b <a href=#>  test</a> c
    <br> a <q>test  </q> b <a href=#>test  </a> c
    <br> a <q>  test  </q> b <a href=#>  test  </a> c

    The key to understand this lies on the explanation of what are ::before and ::after. According to MDN, they create a pseudo-element that is the first (for ::before) or last (for ::after) child of the element matched. So you can imagine that an inline element with a quote inside was added as the first child of each <q>.

    For example:

    <br> a <span><span>"</span>    b</span>
    

    Shows one space before b, while:

    <br> a <span>    b</span>
    

    Does not show the space before b.

    You can see it in action here:

    body {
      font-size: 200%;
    }
    
    q {
      background-color: #AAF;
    }
    
    a, span {
      background-color: #FAA;
    }
    <br> a <q>test</q> b <a href=#>test</a> c
    <br> a <q>  test</q> b <a href=#>  test</a> c
    <br> a <q>test  </q> b <a href=#>test  </a> c
    <br> a <q>  test  </q> b <a href=#>  test  </a> c
    <br> a <span><span>"</span>    a</span>
    <br> a <span>    a</span>