Styling of PEPs

Hugo’s use of the phrase “system font stack” reminded me of where my inspiration for the monospace fonts came from – this post on StackExchange’s design subsystem. (more for historical interest than anything else)

I took Source Sans Mono from/for consistency with pythondotorg. Generally happy with using system fonts, I will prepare a PR a little later today.


This is an important concern – whilst on mobile and under media queries lines will wrap, on desktop especially a single line should fit at least 79-80 characters.


1 Like

TL;DR: I strongly suggest keeping the webfont, status quo for now with the sans body font and considering any site-wide change separately. Instead, you can set pre, code to use a similar webfont (i.e. Inconsolata, from the same source, Google Fonts, as the current sans font), and set its size accordingly to match.

The problem is, there’s no firm standard for how large a font should render at a given “point” or “pixel” size—especially for monospace fonts. In my experience with typography and UI, Helvetica (and Arial, its cheap clone) tends to be at the larger end of things (though fairly consistent with most sans fonts, which tends to be a good 10%+ larger than serif fonts at the same size—compare, e.g. Times/New/Roman vs. Helvectica/Arial). While it is somewhat different from Source Sans Pro, the latter is a webfont, which means it will get deployed consistently across all devices, and we can thus reasonably rely on it.

The monospace fonts that are currently used, however, are more variable, and a webfont is not used, thus users can (and are, based on the availability of the choices) likely to get any one of them depending on their OS and what they have installed; this will in turn greatly affect whether the monospace font looks out of proportion with the body font, and how many characters will fit on one line (79 or not):

  • Cascadia Mono (potentially future Windows, user-installed): 77 char; Larger than the body text, but a little slimmer horizontally than DejaVu
  • **Segoe UI Mono (newer Windows?): Unable to test; proprietary (AFAIK) and don’t have it on my machine
  • DejaVu Mono (some Linux, user-installed): 75 char; Looks much larger (H & V) than body font.
  • Consolas (most Windows): 85 (!)char; Close match to body font; substantially smaller (H & V) than DejaVu
  • Lucida Console (old Windows, maaaybe some Mac?): 76 char, similar vertical size to Consolas but similar horizontal size to many of the others, looks bigger than the body text overall
  • monospace (Likely fallback on most Macs, since no Mac-specific option is specified): On Windows this is Courier, but not sure if it resolves to the same on Mac

Each also has a quite different look, with some (Consolas) look better and more readable than others (Courier), and take up different amounts of vertical, horizontal and line spaceing. Further, I’m not sure any default Mac options are present at all. And there’s also Android, other Linux distros (that don’t have DejaVu), BSD and others to consider.

Instead of trying to find an unhappy compromise, test and balance many different OSes, versions and user configs or pick the lowest common denominator, I suggest simply using a web font to get consistent results on all platforms.

Source Sans Pro is the distinct font used on the rest of the Python website. Any change here should be coordinated with the rest of the site, so there isn’t an incohorent mix of fonts and styles used and the Python site has a cohesive look. Arial looks particularly alien compared to the old PEPs. I’d suggest deferring any such major change until after the initial implementation of the new build system, so as to avoid getting stuck bikeshedding over this.

While there’s definitely an argument to be made for using the system font stack on other sites, especially web apps and platforms, so as to feel cohesive with the system UI, there are some strong reasons not to in this specific case, and many of the cited reasons aren’t necessarily applicable here. Focusing on the three main points made by

Fast: No network request, no time to parse a font, no flash of an incorrect font.

The site already uses a webfont for the body text and I’ve never noticed any meaningful delay, and the cost is only really paid once, on first load.

Styles and Unicode: System fonts have lots of styles and broad language coverage, unlike many webfonts.

We’re already constrained to the limited styles (bold, italic, bold-itlatic) available in reST, and the PEP repo is in English; with only names and special-cases in other languages, with all the characters we’ve needed thus far covered by our existing fonts.

Familiarity: Web apps feel more native when they use system font faces.

The PEPs site isn’t a “web app”; the primary task of the body font is to display prose content, not UI (unlike many of the sites quoted as adopting it, e.g. GitHub). It should be familiar to those seeing other parts of the Python site and to the previous PEP pages, and present a unified cross-platform appearance per Python itself.

In addition, there are some pretty strong reasons why not to in this case:

  • As demonstrated above, there is no guarantee that the sans and mono fonts chosen will match, as they should here (not the case for most sites), nor that the mono font will be a certain line length, unlike with a webfont
  • The appearance of the site will look and behave substantially on different OSes, versions, users configs and even browsers (see the bugs reported there), requiring much more testing and potential for issues, versus a webfont looks and works the same on all
  • Because of the differences, we would have to pick an unhappy medium for font size, line height, etc. that would look okay on the average client but not so good on others
  • This would create an substantial inconsistancy between the look of the PEPs site and the rest of, unless we change everything, unlike using the existing webfont
1 Like

Very quickly (catching a train!) – I sympathise with the consistency argument, but e.g. the Python docs (which I assume get more hits than itself) use Arial & monospace

(from classic.css, L21-L28)

body {
    font-family: 'Lucida Grande', Arial, sans-serif;
    font-size: 100%;
    background-color: white;
    color: #000;
    margin: 0;
    padding: 0;

(from pydoctheme.css, L153-L156)

tt, code, pre {
    font-family: "monospace", monospace;
    font-size: 96.5%;

Will respond to the rest of the post later (post train!) – thanks for the detailed comments, by the way :slight_smile:


1 Like

That’s a good point. Still, though, at least up until now the PEPs have been much a part of the main Python website compared to the docs, which were its own thing and part of the language itslef. Furthermore, the docs were presumably designed before modern webfonts were widely supported and used, and as a legacy least common denominator, represent the worst of both worlds (openly decried by both webfont and system font stack camps alike; e.g. the system font stack site devotes considerable space to maligning Arial and Courier) aren’t something I think we should be constrained by, when that would be a step backward from either the status quo or the system font stack proposal (rather, they should presumably eventually be updated to either use webfonts or a system font stack approach, either being a major improvement over the existing status quo there—but I digress).

Safe travels, and enjoy your trip!

1 Like

I regret bringing up typography!

True, although a poor man’s proxy is matching x-heights – e.g. through Test page for estimating the relative x-height (aspect ratio) of a font, using JavaScript

From this list of python sites (including pythondotorg)

body text

  • Source Sans: www
  • Arial: bugs, buildbot, docs, packaging, speed, wiki
  • Segoe UI: devguide, mail
  • proxima-nova: status


  • Consolas: www, buildbot, devguide, mail, status
  • monospace: bugs, docs, packaging
  • Inconsolata: speed (doesn’t include the font as a stylesheet, so falls back to monspace)
  • Courier: wiki

system font stack (or similar)

  • devguide (through furo)
  • mail

The point here is that there is no real consistency – and the style is already a break from pythondotorg, so I don’t think we should be constrained by that – although it should be a consideration. At one point in this thread I argued that pythondotorg should probably be more of an advertising site for the project/language/charity, and should be purely focussed on hosting PEPs. This might lead to different typographic choices between the two sites. I also think now is the perfect time to switch the typefaces (if we choose to), as no-one is really used to the new design, and so there will be fewer complaints.

Not actually possible in reST without significant hacks :wink: (Docutils doesn’t allow nested markup, that’s on my to do list to look at)

The full list of characters used in the PEPs repo is below in a details block. I was surprised by how large the list was, to be honest. A large number are in PEP 672 (unicode security), PEP 536 (there’s a zalgo block on line 171), PEP 538 (coercing the C locale to UTF-8).

Characters in PEPs and verification script (click to expand)
from pathlib import Path

characters = set()
for path in Path(".").glob("pep-????.*"):

assert characters == frozenset({
    # ASCII / C0 Controls and Basic Latin
    "\t", "\n", "\f",
    " ", "!", '"', "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/",
    "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?",
    "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
    "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_",
    "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
    "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~",
    # Latin-1 Punctuation and Symbols
    "\xa0", "¢", "§", "®",
    "°", "±", "µ", "½",
    "Å", "É",
    "×", "Ø", "ß",
    "à", "á", "ä", "å", "ç", "è", "é", "í", "ï",
    "ñ", "ó", "ö", "ø", "ú", "ü",
    # Latin Extended-A
    "č", "ğ", "Ł", "ň", "š", "ż",
    # Latin Extended-B
    "ƛ", "ƴ",
    # Spacing Modifier Letters
    # Combining Diacritical Marks
    "̀", "̂", "̃", "̄", "̆", "̇", "̉", "̊", "̍", "̏", "̒", "̓", "̔", "̗", "̘", "̙",
    "̛", "̜", "̝", "̞", "̟", "̡", "̣", "̤", "̦", "̧", "̨", "̩", "̪", "̫", "̬", "̭",
    "̮", "̯", "̲", "̴", "̷", "̹", "̺", "̻", "̼", "̽", "̾", "̿", "ͅ", "͆", "͇",
    "͈", "͉", "͍", "͎", "͏", "͐", "͑", "͒", "͓", "͔", "͗", "͙", "͚", "͜", "͠",
    "͡", "͢", "ͤ", "ͥ", "ͧ", "ͨ", "ͩ", "ͮ", "ͯ",
    # Greek and Coptic
    "Β", "ά", "α", "β", "γ", "ε", "ο", "π", "τ",
    # Cyrillic
    "В", "Д", "Н", "С", "а", "б", "в", "е", "и", "к", "л", "м", "н", "о", "р", "с",
    "т", "у", "ц", "я", "ѕ",
    # Hebrew
    "א", "ך", "ע", "ר",
    # Arabic
    "ة", "ق", "م", "ي", "٥",
    # N'Ko
    # Bengali
    # Oriya
    # Tamil
    # Latin Extended Additional
    "Ḛ", "Ṯ",
    # Greek Extended
    # General Punctuation
    "\u200b", "\u200f", "–", "—", "‘", "’", "“", "”", "…",
    # Superscripts and Subscripts
    # Letterlike Symbols
    "ℂ", "ℌ", "ℕ", "ℙ", "℮",
    # Arrows
    # Mathematical operators
    "∀", "∃", "∅", "⊗", "⋅",
    # Miscellaneous Technical
    "⌁", "⌚",
    # Enclosed Alphanumerics
    # Box Drawing
    "─", "└",
    # Miscellaneous Symbols
    "☂", "☃", "☺", "♨", "⚛",
    # Dingbats
    "✎", "✒", "✓",
    # Miscellaneous Mathematical Symbols B
    # Miscellaneous Symbols And Arrows
    # Katakana
    "ス", "パ", "ム",
    # CJK Unified Ideographs
    "十", "大", "学", "屆", "年", "日", "曜", "月", "槀", "櫰", "波", "激", "火", "筑", "粹", "羔", "鈩",
    # Alphabetic Presentation Forms
    # Halfwidth And Fullwidth Forms
    # Fullwidth Latin
    # Halfwidth And Fullwidth Forms
    # Specials
    # Mathematical Alphanumeric Symbols
    # Mathematical Alphanumeric Symbols
    # Miscellaneous Symbols And Pictographs

I agree. Equally though, macOS/OS X fundamentally look and feel different to Windows or Linux, and the cognative dissonance might be greater in an unfamiliar typeface than in different typefaces cross-platform.

I do have a personal preference for system fonts, partially due to the extra simplicitly of using built-in tools, extra familiarity, and not having to make a choice over font display. The reason I am hesitant though is that especially for PEPs, we should really make sure that a single line of literal/code display holds at least 80 characters, and I don’t know how we can guarantee that in the best way. (We could increase the margins of course, but there will always be someone with a really esoteric setup.)

I appreciate this is a lot of fence sitting! I’ll wait a day or two to allow anyone who wants to to voice an opinion, but otherwise I’ll have a look and propose a concrete suggestion as a PR to the peps repo.


1 Like

A fair point. Could a moderator split the recent “style/typography” posts to a new thread?

A decision on the documentation, mainly.

That is more to tie up loose ends though, and isn’t a blocker to the PEP itself.

Thanks @encukou, very kind!


1 Like

Yep, just provide a link to the comment to start the split at and I can do it for all subsequent replies.


That’s almost certainly mine, and most messages since then have been about style


Thanks @encukou , and sorry about that—those are really details that are far below the PEP level ,and I’m probably the worse offender there. @brettcannon Yeah, like @EpicWink basically everything after that comment can be split, as it is almost exclusively related to details of the style, typography, rendering, etc (and to be clear, more my fault than anything) rather than the PEP itself. Once the thread is created, I’ll reply there with my further feedback (glad I took a break from it for a bit, or this OT thread would be even longer, heh).

1 Like

Thanks @brettcannon, I agree Laurie’s post is where I’d start (

1 Like

Dark mode:

This image (and possibly others) need adapting for dark mode:

One option is to replace the background transparency with white, and show it white in dark mode.

Another is to switch the image for another with a dark background.

Or use filter: invert(1) CSS (for example), which would give something like:


Good catch; I just noticed that too.

This was my first thought too, but it wouldn’t look so good and still require modifying each original image to add it, a non-trivial amount of work especially for older PEPs, and which wouldn’t look as good anyway.

I’m personally a bit averse to bespoke hacks in the dark theme CSS/JS for specific PEPs, which switching the image would require, as far as I’m aware.

This seems like the best solution; anchors as in the linked example technically work (via .. invert-image: or similar) but only for one image per page; .. rst-class:: invert-image is a much cleaner solution. CSS filters and the invert() function should be usable on all browsers we support.

One note about SVGs: per MDN via caniuse, “CSS property: filter: On SVG element” is listed as unsupported for all browsers but FF, so if images are not dark mode compatible, we would need to retain PNGs for those images (which currently all displayed images are).

I surveyed the other images that might need this; expand the details sections to view screenshots

1 Like

Thanks both for the detailed investigations.

I’m reticent to do much significant work here in the design space. What’s the prior art for handling images in websites with “well implemented” / thoughtful dark modes?

If every image was an SVG (it looks like most could be made SVGs), it would be possible to do CSS variable styling, but I really don’t want to get that complex.

Filter invert also seems pretty odd on the ones with colours outside of pure black/white/grey, but is simple.


Generally speaking, in my limited experience browsing and creating such, graphics/UI elements/line art either has transparent backgrounds and color choices that contrast well with both surrounding colors, or alternate versions for the light and dark themes that get swapped in via CSS. We’re dealing with a somewhat different case than most here in that pretty much all the images are inline in the content, not part of the site UI, and are plots, charts and other line art rather than photographs, graphics, etc, and where they contain critical information, not just decorate or even just complement the text.

Yeah, but we’d need to inline the SVGs into the page, filters wouldn’t work and we’d be dealing with the complexities of browser SVG feature support, which is a whole other can of worms, and the practical reality is that we only have SVG versions for a couple of the images.

Yeah, I noticed, but without more complex manipulation I’m not sure of an easy way around that. The most conservative approach would be only applying it to the cases where it is strictly necessary for all elements of the figure to be visible (i.e. :arrows_counterclockwise: , not :arrows_counterclockwise: :white_check_mark: ), even if those with white backgrounds do look rather blaring in the dark theme.

With a bit of work we could potentially provide a CSS class-based mechanism (or even a custom Sphinx directive) to swap out images for light and dark versions if future authors provide them, but that’s a lot of work on both sides for a relatively modest benefit for a small number of cases.

I had a look at the new PEP website and, as has already been brought up in this thread, there’s a minor quirk with the formatting of PEPs on the new site, e.g. PEP 630 – Isolating Extension Modules |

Code snippets in the text are rendered much larger than regular text, which looks odd.

The fix is easy: simply add a font-size to the pre, code CSS:

pre, code {
  font-family: ui-monospace, "Cascadia Mono", "Segoe UI Mono", "DejaVu Sans Mono", Consolas, monospace;
  white-space: pre-wrap;
  word-wrap: break-word;
  -webkit-hyphens: none;
  hyphens: none;
  font-size: 0.8rem;

With this change the code snippets look “right” again (at least in my browsers).

Thanks for posting here. As mentioned in my reply on the other thread directing you here, this issue in particular has been discussed at length above (without resolution yet).

The issue is that the apparent size is quite different between the different font options in the (system) font stack, so a size that works for one font to match the sans font won’t work for another. My proposed simple solution to this is to just use a web font like Inconsolata, while others preferred using a standard system font stack, which has some (in my view modest) advantages, but results in different looks on different OSes, versions, browsers, etc. (requiring much more testing and leaving us open to edge cases like this) and in particular, depending on the variable combination of sans and mono fonts, resulting in the two potentially having very different sizes (in different directions) depending on which combination a system happens to have.

It’s fairly common for websites to use a smaller font size for inline code.

Most Sphinx themes already do this. I don’t see why PEPs shouldn’t do the same?

Beyond that, 0.8125rem would result in a round number font size in px, which might be desirable. :slight_smile:

1 Like

There’s no indentation for definition lists, which negatively affects some PEPs (I saw this on 609).

The whitespace (line height + margin) for paragraphs and heading seems… somewhat tight which makes it a bit difficult to read. Would a PR adjusting these be welcome? Notably, do people consider something like this controversial?

I see that the font question is going through a bunch of discussion, and I’m gonna keep away from it. If someone has mentioned using the system font stack, great. Otherwise, I’ll note that it’s an option and also what Furo uses.


Yes, I’d say PRs to improve readability, usability, accessibility and so on are welcome especially when backed up by best practices / WCAG etc.