Periodic Table of the Elements

Might 8, 2019; three Feedback

I constructed this for me. An viewers of one. A strategy to hold sharp the expertise that I’m not all the time in a position to use on a venture.

My necessities have been easy: responsive (print, small screens), accessible (beyond display readers), and kinda fun. Since it relies on a JSON knowledge supply it already requires JavaScript to perform, however it still incorporates progressive enhancement (akin to IE10 grid help). It skimps on supporting RTL languages because I do not know how the real-life Periodic Table of the Elements adjusts for these languages. See, I’m not a chemist. Nor scientist.

A word of warning — this publish is a few desk of parts that is made up of non-table parts. If that sentence made no sense, then it is best to take pleasure in this. In other phrases, I’ll use the phrases desk and factor in a complicated trend.

See the Pen
Periodic Table of the Elements by Adrian Roselli (@aardrian)
on CodePen.

Toggle between 1×, 0.5× and 0.25× in the bar at the bottom of the embed to see it change. It’s also possible to go to a debug model of the demo, which removes all the CodePen wrapper and script.


Common Notes

I asked on Twitter about sharing this as a tutorial or only a fat Codepen. The overall suggestions was tutorial. Then I noticed I made a suggestion I couldn’t honor owing to time constraints. So I wrote this as an alternative. An summary of a work in progress.

I constructed this to lean on as few dependencies as attainable. Custom fonts could also be a given, but generally there isn’t any purpose you can’t lean on a system font. While I dislike that Segoe, Helvetica, Roboto, and others make it exhausting to differentiate a 1 from an l from an I, for my objective they are ok.

This demo additionally doesn’t set a base font measurement. It uses ems and rems for sizing, which means it can key off the consumer’s default text measurement, whether actively chosen or not. It is going to also honor the consumer’s zoom setting.

I present code snippets all through this submit, however they are typically trimmed or taken to point out just one facet at a time. The code blocks in this publish don’t include all the things that is occurring in the demo.

The Knowledge

The info comes from Periodic-Table-JSON, a JSON version of the Periodic Table of the Elements, and is used underneath Attribution-ShareAlike Unported (CC BY-SA Meaning that you could build your personal Periodic Table of the Elements from the similar source, or prolong it to include info not in there now. You possibly can take my parsing script and make it into any HTML structure you need.

Following is simply the Molybdenum knowledge (with the ionization energies stripped) for instance of the construction.

“name”: “Molybdenum”,
“appearance”: “gray metallic”,
“atomic_mass”: 95.951,
“boil”: 4912,
“category”: “transition metal”,
“color”: null,
“density”: 10.28,
“discovered_by”: “Carl Wilhelm Scheele”,
“melt”: 2896,
“molar_heat”: 24.06,
“named_by”: null,
“number”: 42,
“period”: 5,
“phase”: “Solid”,
“source”: “”,
“spectral_img”: null,
“summary”: “Molybdenum is a chemical element with symbol Mo and atomic number 42. The name is from Neo-Latin molybdaenum, from Ancient Greek u039cu03ccu03bbu03c5u03b2u03b4u03bfu03c2 molybdos, meaning lead, since its ores were confused with lead ores. Molybdenum minerals have been known throughout history, but the element was discovered (in the sense of differentiating it as a new entity from the mineral salts of other metals) in 1778 by Carl Wilhelm Scheele.”,
“symbol”: “Mo”,
“xpos”: 6,
“ypos”: 5,
“shells”: [
“electron_configuration”: “1s2 2s2 2p6 3s2 3p6 3d10 4s2 4p6 4d5 5s1”,
“electron_affinity”: 72.10,
“electronegativity_pauling”: 2.16,
“ionization_energies”: [


Take note of xpos and ypos as those will come in useful for format.


The primary place I started for the format was choosing my HTML. I need to characterize the atomic parts in a method that preserves which means when only the semantics and construction of the page can be found. Since there are a finite quantity of atomic parts and their place in an general rely is necessary, I opted for an ordered listing (

    ). Every atomic factor lives in an inventory item (

  1. ), natively presenting a rely for display reader customers.

    Notice that VoiceOver does not help record nor listing merchandise navigation. Since every record merchandise also has a button, that permits VoiceOver customers a method to shortly transfer by means of the atomic parts. Right here is my HTML for Molybdenum:

  2. 42

  3. Detail of some elements in the table.Some of the atomic parts in context.

    Observe that I don’t outline each bit of textual content in the field. Once a reader (me) is aware of what each means, it simply adds visual noise. Additionally it is too verbose for display reader users (if I hid it visually) for the similar purpose.

    As soon as I have carried out the most applicable HTML construction I can move on to styling. That is the means all of us do it, proper?


    At this level assume I’ve constructed the format for the content material in every individual field (the

  4. holding the atomic factor information). I need to ensure this can be extra helpful than a long-scroll stack of bins. Not all browsers help CSS grid, and a few viewports shall be too slender to point out a legible Periodic Table in all its broad glory.

    So, like a sinking container ship with a load of ping pong balls, I simply float them all.

    #Elements li
    float: left;

    #Elements ol::after
    content material: “”;
    display: block;
    clear: left;

    The boxes running 4 across, almost filling the viewport before starting a new row.As seen in a slender, non-grid view.

    CSS Grid

    Now we will interact in slightly progressive enhancement with function queries. For slender viewports I do not need grid. I can wait till a wider viewport, however right here I can at the very least begin the ball rolling. I undo all the floats and grid them all (like a waffle maker?). Notice I’m not even making an attempt to assist Web Explorer here. Floats are ok for IE.

    @supports (display: grid)
    #Elements li
    float: none;

    #Elements ol::after
    content material: none;

    #Elements ol
    show: grid;
    grid-template-columns: repeat(auto-fill, minmax(8em, 8em));

    That final bit with the auto-fill simply slots in as many 8em packing containers will match earlier than shifting to the next row. That last bit can also be why I ditched IE help on this step. I received caught, couldn’t get the syntax right for IE, realized floats have been ok at this viewport width, and moved on.

    The boxes running 4 across, almost filling the viewport before starting a new row. But now they have a square aspect ratio.Still a slender view, however with grid utilized.

    Large Viewport

    Once we get to a sufficiently broad viewport (at an arbitrarily chosen minimal text measurement) we will arrange our 18 column grid. Conveniently, we all know exactly what number of columns and rows to make use of, and much more conveniently the JSON tells us the place to put each atomic component in the grid.

    I grabbed the xpos and ypos values I mentioned above and made them into courses. Recall the HTML for the Molybdenum instance above.

  5. […]
  6. Observe the row5 and col6 courses. That tells me exactly the place to drop it in the following grid.

    @media all and (min-width: 60em)
    #Elements ol
    font-size: .67vw;
    show: -ms-grid;
    -ms-grid-columns: 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em;
    display: grid;
    grid-template-columns: 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em;

    grid-row: 5 / 6;
    -ms-grid-row: 5;

    grid-column: 6 / 7;
    -ms-grid-column: 6;

    You might have observed some -ms-grid properties. Adding them shouldn’t be exhausting, and it permits your grid layouts to work for Web Explorer customers. Somewhat additional testing, some redundant types, and also you internet even more customers. I contemplate that a differentiator for a website (or a developer).

    The table with the full layout in a maximized browser window.The view when it has all the room it wants.

    Less Broad Viewport

    Fun reality — not everyone surfs in a large window. Some customers are on tablets, some customers have rotated their screens to portrait, some users have zoomed into the web page, some customers run with giant fonts. In these instances the place the viewport is broad sufficient to carry 10 columns of knowledge (at an arbitrarily chosen minimal textual content measurement), you’ll be able to flip the Periodic Table on its head aspect.

    I flip it to be learn from the right, following a follow I picked up again in my structure days. That brings with it the problem that keyboard focus will start at the backside of the format and work its method up. I can play around with rotating elements of the table or doing other tips (as I did in my GitHub contributions chart rebuild), however I’m going to think about this a training situation. If the desk must be learn from the left, this can be a nice alternative for a read to fork it and check out it.

    I arrange my class names and types for a wide view, which makes for a somewhat complicated set of grid types when taking a look at the class names in the much less broad view. However no matter. You do you once you make your personal.

    @media all and (min-width: 40em)
    #Elements ol
    font-size: 1.18vw;
    display: -ms-grid;
    -ms-grid-columns: 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em;
    show: grid;
    grid-template-columns: 8em 8em 8em 8em 8em 8em 8em 8em 8em 8em;

    grid-column: 5 / 6;
    -ms-grid-column: 5;

    grid-row: 13 / 14;
    -ms-grid-row: 13;

    That’s about all it is advisable to get your primary format.

    In a narrow window, with table flipped on its side but the text still legible from straight-on.The same table, but primarily rotated to be read from the right.


    There isn’t any cause that you simply can’t print this. No purpose aside from browser wonkiness.

    I would like my sideways view to print when the paper is portrait, taking over as much area as potential. I do this by messing with the font measurement to get what I need to set off the 40em media query.

    @media print
    #Elements ol
    font-size: .7vw;

    For the wider view in panorama, similar idea but with an adjusted media question.

    @media print and (orientation: landscape)
    #Elements ol
    font-size: .63vw;

    Sadly, I can only get this work persistently in Firefox.

    Full color layout in landscape view in Firefox print preview.Full color rotated layout in portrait view in Firefox print preview.Print previews from Firefox.


    The advantage of a web-based Periodic Table of the Elements is that you can do more than just present static text. With all the knowledge coming from the JSON file I’ve some choices, although all the stuff most respected to scientists might be meaningless to me.

    Zooming Elements

    There’s a affordable probability that the text shall be too small to learn in the default layouts. I began to work out a strategy to get around it by zooming right into a box when hovering over it or putting focus in it. Perhaps not a super answer, however I moderately favored the way it made the relevant component pop for me.

    Whereas a hover fashion can be enough for only a mouse it also should help keyboard. I needed to avoid rather a lot of pointless JavaScript handlers and, owing to an viewers of simply me, opted for a CSS answer in :focus-within. Word the types in :focus-within are redundant owing both to lack of browser help and that their presence with hover types will break them utterly in non-supporting browsers.

    I additionally only set off this conduct when I’ve scaled the text down, which suggests as soon as I begin to lay out the desk.

    @media all and (min-width: 40em)
    #Elements li:not(#Key):hover
    rework: scale(2);
    z-index: 120;
    box-shadow: 0 0 1em rgba(zero,zero,0,.eight);

    /* Merge with above when :focus-within is supported */
    #Elements li:not(#Key):focus-within
    rework: scale(2);
    z-index: 120;
    box-shadow: 0 zero 1em rgba(zero,0,0,.eight);

    I am excluding any listing gadgets that have id=”Key”. I don’t need the class key to ever scale.

    For gadgets on the outdoors columns, I scale them from the edge as an alternative of the middle to stop window clipping and horizontal scrollbars. I discovered it easier to place an higher sure on the media query triggering it than to reset the transform-origin in the wider viewport, but that was principally my mood at the time.

    @media all and (min-width: 40em) and (max-width: 60em)
    #Elements li.row1:hover
    transform-origin: left;

    #Elements li.row10:hover
    transform-origin: proper;

    #Elements li.row1:focus-within
    transform-origin: left;

    #Elements li.row10:focus-within
    transform-origin: right;

    @media all and (min-width: 60em)
    #Elements li.col1:hover
    transform-origin: left;

    #Elements li.col18:hover
    transform-origin: proper;

    /* Merge with above when :focus-within is supported */
    #Elements li.col1:focus-within
    transform-origin: left;

    #Elements li.col18:focus-within
    transform-origin: right;

    Molybdenum getting focus or hover.

    Spotlight Categories

    You might have observed that the atomic parts are colour coded and that there’s a key to help determine what each shade means. I get the class text from the JSON, convert each to unbroken strings, and append them as courses to each atomic factor’s listing merchandise.

    // Get the class and concatenate into the class
    var rawCat = json.class;
    var stringCat = rawCat;
    stringCat = stringCat.cut up(‘ ‘).be a part of(‘_’);
    stringCat = stringCat.cut up(‘,’).be a part of(”);
    elementNode.classList.add(“cat-” + stringCat);

  7. […]
  8. It is very important know that whereas the key seems visually in the gap at the prime of the Periodic Table, it lives as the final record item of the general collection. If I had put it first, then each atomic aspect would have an inventory position one off from its atomic quantity.

    It also means the tab order could also be totally different than a consumer expects, although for display reader customers I try and mitigate that by making the textual content “Category key” an

    to make it simpler to jump proper to the key. Should you marvel why a display reader consumer would care about seeing this, keep in mind that not all display reader users are blind.

    The catch in my design is that it is probably not straightforward to tell the category colors apart. I tackle that by allowing the consumer to hover (or tab to) each item in the key. For Molybdenum, the button appears like this:

    The ToggleStyleBlock() perform simply writes (or removes) CSS rules that make all record gadgets that are not the similar class primarily lose their background.

    “#Elements li:not(#Key):not(.” + strClass + “) background-color: #999; opacity: .5; ”,0
    “@media screen and (prefers-color-scheme: dark) #Elements li:not(#Key):not(.” + strClass + “) background-color: #333; opacity: .5; ”,1
    “@media screen and (-ms-high-contrast: active) #Elements li:not(#Key):not(.” + strClass + “) opacity: .25; ”,2

    Chances are you’ll discover that two of those rules use function queries, specifically the proprietary -ms-high-contrast for Windows High Distinction Mode, and the now commonplace prefers-color-scheme for users operating a darkish theme.

    Sorry, your browser doesn’t help embedded videos, however don’t worry, you’ll be able to download it.
    Displaying the transition metals solely.


    The dialog is a bit of a multitude. That’s principally owing to the poor help across browsers for easy methods to properly prohibit focus to a dialog without breaking the browser and partially owing to it not being the factor I needed to play with right here.

    Proper now, help for native is poor, and the polyfill (which I’m not linking) doesn’t assist the place it actually matters most — assistive know-how. Scott O’Hara particulars the issues in his submit Having an open dialog. As an alternative I built a customized dialog usually based mostly on the following pointers from Scott O’Hara with the inert polyfill to make it at much less awful.

    In any case that, the dialog nonetheless has some gotchas for tall screens, and some display reader and browser mixtures. The problem here is that for an viewers of just me it works effective as you see it. Principally. Either means, do not copy it. But.

    I do handle the essential gadgets, nevertheless. The dialog’s close button receives focus when it opens so I can hit Enter instantly to dismiss it (focusing the modal itself can be nice). It additionally goes away with a press of Esc or a click on outdoors the modal. My script shouldn’t be, let’s consider, good, however it does the job.

    As for the format in the modal, properly, I merely received tired of engaged on it. I’ll replace the format in the future. In any case, I already know I’ll come again and tweak the modal over time. Chances are you’ll discover that the

    splits into two columns, however typically splits between a

    and its following

    . So yeah, work to be carried out there.

    A box of text blocking the view of the table behind it.A sloppy, yet passable, dialog.


    I’ve made selections throughout to deal with accessibility. I have been cautious about the HTML parts I’ve used. I have thought-about the reading and tab order. I’ve ensured that interactive controls are native. I’ve accounted for consumer preferences on textual content measurement. I have in all probability made other selections which might be reflex that I didn’t even contemplate. All of these are built-in into the preliminary build. Here I’ll touch on some specific selections I made that make the expertise better for everybody.


    For the contrast, I ensured that the background colour for each category sort had at the very least a four.5:1 distinction ratio with the text — although as you possibly can see in the display shot I used to be actually at about 19:1 contrast ratio.

    The Colour Contrast Analyser alongside an element showing the colors and ratio.A single aspect displaying the distinction ratio using the Color Contrast Analyser.

    The remaining of the distinction was straightforward. White magnifying glass icon on a black background, reversed on focus/hover? Straightforward. Whereas I didn’t make that shade choice for accessibility reasons, it definitely proved simpler.


    For each of the buttons I exploit aria-labelledby and point to each the textual content in the button, which is visually hidden, and the aspect (or class) identify. I lean on this over aria-label as a result of machine translation providers akin to Google Translate won’t translate aria-label.

  9. 42

  10. transition metallic

    Sorry, your browser doesn’t help embedded videos, however don’t worry, you’ll be able to obtain it.
    NVDA / Firefox talking the component button: Molybdenum details. Button.NVDA / Firefox talking the class button: Highlighting transition metallic button.

    Decreased Movement

    There are two instances of issues on the display flying at the consumer — the individual atomic parts and the modal. As a result of these animations are CSS, I can use a prefers-reduced-motion function question to disable them.

    #Elements li
    transition: rework .05s ease-in-out,
    box-shadow .2s ease-in-out,
    background-color .2s ease-in-out;

    transition: rework .1s ease-in, opacity .2s ease-in;

    @media display and (prefers-reduced-motion: scale back)
    #Elements li, [role=”dialog”]
    transition: none;

    Dark Mode

    Typically I will simply invert the whole web page with CSS for a dark mode, but I didn’t look after the colours it produced for each of the classes. So I took a while to seek out darker variations of every category shade that also maintained a minimal 4.5:1 contrast ratio (however nonetheless truly nearer to 19:1) with the white text.

    I stuffed all that in a prefers-color-scheme: darkish function query, along with general web page colour modifications, and was off to the races. To me it seems like an Easter night time scene.

    background-color: #F0FEAB;

    @media display and (prefers-color-scheme: dark)
    background-color: #676C4A;

    The full-width table as seen with darker colors on a black background in Firefox.The dark mode as seen in Firefox.

    Windows High Distinction Mode

    Windows High Contrast Mode (WHCM) is a function that solely comes in Home windows. It primarily dumps most colours and makes use of a handful of system colours as an alternative, overriding many of your types. I have written about WHCM a number of occasions right here.

    Principally I add an overview to the buttons and reset the background colour, leaning on the keyword windowText. I additionally swap the SVG for customers who have gone to a darkish high distinction theme.

    Since I’m already altering opacity for atomic parts when I’m exploring classes, this carries over to WHCM with no modifications needed.

    @media display and (-ms-high-contrast: lively)
    #Elements li button:focus, #Elements li button:hover
    outline: 1px windowText dotted;
    background-color: windowText;

    @media display and (-ms-high-contrast: white-on-black)
    #Elements li button
    background-image: url(“data:image/svg+xml;charset=utf8,%3Csvg xmlns=’’ viewBox=’0 0 100 100’%3E%3Cpath d=’M71.77069 61.87311a36.53064 36.53064 0 1 0-9.89917 9.89868l21.1792 21.17792a6.9996 6.9996 0 1 0 9.89844-9.89942zM41.49994 64a22.5 22.5 0 1 1 22.5-22.5 22.52554 22.52554 0 0 1-22.5 22.5z’ fill=’%23fff’/%3E%3C/svg%3E”);

    #Elements li button:focus, #Elements li button:hover
    background-image: url(“data:image/svg+xml;charset=utf8,%3Csvg xmlns=’’ viewBox=’0 0 100 100’%3E%3Cpath d=’M71.77069 61.87311a36.53064 36.53064 0 1 0-9.89917 9.89868l21.1792 21.17792a6.9996 6.9996 0 1 0 9.89844-9.89942zM41.49994 64a22.5 22.5 0 1 1 22.5-22.5 22.52554 22.52554 0 0 1-22.5 22.5z’ fill=’%23000’/%3E%3C/svg%3E”);

    [role=”dialog”] button, [role=”dialog”] button:focus, [role=”dialog”] button:hover
    background-image: url(“data:image/svg+xml;charset=utf8,%3Csvg xmlns=’’ viewBox=’0 0 100 100’%3E%3Cpath d=’M50 0a50 50 0 1 0 0 100A50 50 0 0 0 50 0zm26.6 76.6a37.5 37.5 0 0 1-53.2 0 37.5 37.5 0 0 1 0-53.2 37.5 37.5 0 0 1 53.2 0 37.5 37.5 0 0 1 0 53.2zm-7.3-45.9a6.6 6.6 0 0 0-9.3 0l-10 10-10-10a6.6 6.6 0 0 0-9.3 9.3l10 10-10 10a6.6 6.6 0 1 0 9.3 9.3l10-10 10 10a6.6 6.6 0 0 0 9.3 0 6.6 6.6 0 0 0 0-9.3l-10-10 10-10a6.6 6.6 0 0 0 0-9.3z’ fill=’%23fff’/%3E%3C/svg%3E”);

    Yes, I’m spending rather a lot of area on managing SVGs whose solely distinction is their fill colour. My choice to lean on plain text inside each button as an alternative of an SVG is how I painted myself into this non-DRY corner.

    A purely black and white version of the table.Purely black and white for the selected category only, the rest is faded.Windows High Distinction Mode as seen in Web Explorer 11.


    There is a lot happening in my demo. JSON parsing, grid format, responsive design, accessible identify calculation, interactions, effing modals, and so forth. Many of these can in all probability be made extra efficient and any of these in all probability misses a use case or edge case.

    By putting this out right here I am opening it up for criticism from those who deeply know a facet, for studying from those new to these things, and totally free bug checking from everyone else. We don’t have peer evaluate in our business, however running a blog your experiments and ideas is about as shut as we will get.

    When you have good concepts for tips on how to visualize the science knowledge I present in the modals, please share something I can steal.


    accessibility, css, html, JavaScript, print, WHCM

    Other Posts

    Earlier submit: Uniquely Labeling Fields in a Table

Related posts
accessibilityBlogbrowserChromeedgeFirefoxInternet ExplorersafariusabilityUXWeb

Group Labels Do Not Guarantee… Uniquity?

AdoreboardanalyticsBlogcustomer centricitycustomer experienceCXdata scienceemotion analysismarginal gains

Are Marginal Gains the Answer to Measuring Customer Experience? – Adoreboard Blog


Old Forge’s new passion: mountain biking


David Gibson On APA Appointments; Role of Statewide Interests –