AtoZ CSS Screencast: The CSS Quotes Property

By Guy Routledge

Loading the player…

This screencast is a part of our AtoZ CSS Series. You can find other entries to the series here.


Single and double quotes appear frequently when writing code.

However, when displaying any quoted text like the q element or when using apostrophes, we should use smart quotes.

These are often added by the browser, but we can control their appearance and the choice of character from CSS.

In this episode about we’ll learn all about:

  • the difference between dumb quotes and smart quotes
  • the different styles of quotes used internationally
  • and the somewhat under-used CSS quotes property

Smart or Dumb?

When we create a string of text in a code editor, we use “dumb quotes”.

These are either ‘single quotes’ or “double quotes” and are straight. The same character is used at the beginning of the string as at the end.

Smart quotes are the correct typographic choice for any quotes or apostrophes that are displayed in the browser. They are often curly or sloped and the start and end quotes are often different.

If your document uses the utf-8 character set you can add smart quotes directly into the HTML with the following keyboard shortcuts on a Mac:

‘ ⌥+]
’ ⌥+⇧+]
“ ⌥+[
” ⌥+⇧+[

And on Windows:

‘ alt+0145
’ alt+0146
“ alt+0147
” alt+0148

Alternatively, the character entities can be used:

‘ ‘
’ ’
“ “
” ”

International Quotes

When researching this episode, it came as a bit of a surprise to me that there is so much variation in the style of quote marks from country to country.

English quotes look “like this” – with left and right double (or single) quotes.

French quotes use right and left «angle quotes».

And »Danish quotes« use the same characters but the other way round.

Bulgarian, Czech, Estonian, Georgian, Icelandic, Russian, Slovak, Slovene and in Ukrainian quotes use the bottom double quote as the open quote and the right double quote to close.

Other countries use a combination of these styles and a table of quote marks can be found on Wikipedia.

quotes in CSS

In CSS, there’s a quotes property that allows us to control how the browser generates quotes for elements like q which is for inline quotations.

q {
  quotes: "“" "”";

The two space separated strings specify the characters to use for the opening quote and the closing quote mark.

It’s possible to use two sets of strings to specify how nested quotes appear.

q {
  quotes: "“" "”" "‘" "’";

With this snippet, any nested quotes will use single curly quotes instead of double curly quotes.

“the quote contained a ‘nested’ quote”

The q element will have quote marks generated by the browser but the blockquote element will not. We can add in quotes using pseudo elements and the content property.

blockquote {quotes:"“" "”" "‘" "’";}
blockquote: before {content:open-quote;}
blockquote: after {content:close-quote;}

These can be styles with any other CSS properties to achieve the desired design result.

Finally, we can combine our knowledge of international quote characters with CSS by changing the quotes property based on the language of the document or part of the document.

We can do this using the :lang pseudo class.

:lang(en) q {quotes: "“" "”";}
:lang(fr) q {quotes: "«" "»";}
:lang(pl) q {quotes: "„" "”";}

Now by changing the language attribute of the html element, our quote marks are corrected for the corresponding language.

I like the idea of getting subtle details like this right in web design, I’m sure it’s something often overlooked but anything that can be done, big or small, to improve user experience sounds good to me.

  • Tracy-Gregory Gilmore

    Guy, Any chance you could provide a link to a working example. I have tried to draft something using example code fragments in the article transcript but none of it works. Maybe this is why it has not been widely utilised? I have tested code in Chrome and IE11 on Windows 7 but in both cases all that is shown is either the text itself (in the case of “ or “) or an unprintable character for “ alt+0147.

  • Tracy-Gregory Gilmore

    Sorted. The issue, as i suspected, was all mine. The sampler file I had prepared was saved in ASCII not UTF-8 format. Once I have downloaded and checked your codepen example, my mistake became obvious. Thank you.

  • Marc

    Hi Guy,

    I’m with you nearly until the end of this article. To me it looks strange and I think people do not understand, when you have an french blockquote in a german text with different quotation marks then the rest of the page – even worse, when you add more languages.

    So I’ suggest to change the quotes only depending on the language of the root element, like so.

    html:lang(en) q {quotes: ““” “””;}
    html:lang(fr) q {quotes: “«” “»”;}
    html:lang(pl) q {quotes: “„” “””;}

    But why someone should do this? If you add all existing languages, you would never need to change this code again. OK – but this is quite a lot of code then and nearly always you know the main language of the site you are working on. So just one definition of quotes should do it.

    Sometimes we work on multilingual sites, where this set of rules can be useful. Maybe this is what you ment (so no offence intended), but it sounded like a general suggestion to me…

    Everything else: thanks for writing this down! Frontenders should care about things like that!

    • Hey Marc, sorry if this wasn’t clear. Your approach of only changing the quotes on the root element is correct and is what I was trying to suggest when saying “Now by changing the language attribute of the html element, our quote marks are corrected for the corresponding language.”

      To your question as to why should you do this, the reason would be to enable switching of quote marks between languages based on the language attribute being used, rather than hard coding quote marks into the text in the HTML or even in a CMS.

      Hope that helps clear things up.

      • Marc

        Sorry, I missed the “Now by changing the language attribute of the html element, our quote marks are corrected for the corresponding language.”
        Thx for making this clear.

        Maybe you can change the code example, so one can see in the example, what the text is about ;-)

        Of course I got the idea of your post. But it works only, if you already know which languages have to be supported (and you add every language which might be necessary in the future by hand) – or you have to build a list for every existing language. That would be really a lot of code.

  • Thanks for a great article! Two questions though about the code:
    blockquote {quotes:”“” “”” “‘” “’”;}
    blockquote: before {content:open-quote;}
    blockquote: after {content:close-quote;}
    Are the two bottom lines correct in that there is a space between the colon and ‘before’/’after’?
    I’d thought that the space should be replaced by a colon — since ‘before’ and ‘after’ are pseudo *elements* as opposed to pseudo classes.

    Also, is it valid to write non-literal values like ‘open-quote’ and ‘close-quote’ — i.e. are these two identifiers some sort of variables — CSS normally does not allow variables except currentColor — that refer to the values set in the first of the three lines?

    • Good catch on the typo. There should not be a space between blockquote and :before or :after.

      open-quote and close-quote are special values – a bit like sans-serif – so they’re not literal strings.

Get the latest in Front-end, once a week, for free.