DEV Community

Cover image for GitHub Readme: Responsive? πŸ€” Animated? 🀯 Light and dark modes? 😱 You bet! πŸ’ͺ🏼
GrahamTheDev
GrahamTheDev

Posted on

GitHub Readme: Responsive? πŸ€” Animated? 🀯 Light and dark modes? 😱 You bet! πŸ’ͺ🏼

Yes, you heard me right, my GitHub readme has light and dark modes and is even responsive. In this article I will briefly cover the tricks I used to make this happen (and the things that made it difficult!)

But first, let's have a look at what my profile looks like at different screen sizes and colour preferences (or go try out GrahamTheDevRel's profile on GitHub for yourself!

Dark Mode

GrahamTheDevRel GitHub profile on Desktop in dark mode. 5 buttons at the top like a menu, Graham with thumbs up next to a speech bubble that says

Mobile

Notice the different button design and layouts for the sections below.

Those buttons were a lot harder to create than you might think!

GrahamTheDevRel GitHub profile on mobile in dark mode. 5 buttons at the top like a menu that show social icons, Graham with thumbs up below a speech bubble that says

Light Mode

I couldn't help but have a different message on the hero section, I am only joking of course! πŸ€£πŸ’—

GrahamTheDevRel GitHub profile on Desktop in light mode. 5 buttons at the top like a menu in black on white colours, Graham with thumbs down next to a speech bubble that says

Oh...and did I mention it is animated?

Bear in mind that those first 5 buttons are each individual images! Took a little fiddling to get it right!

GrahamTheDevRel GitHub profile where the menu buttons animate in after a delay, followed by Graham next to a speech bubble animating in shortly after

Some tricks used!

OK, so you didn't come here just to see my profile! (and if you did, love you too! πŸ€£πŸ’—)

No, you came to learn some tricks so you could do it yourself right?

Well, there is one "trick" and then just one HTML feature that you need to be able to do this yourself.

Let's start with the most interesting one:

The trick to make responsive buttons and images!

The buttons and the hero image on the website are the interesting part.

To make them work we use a SVG feature not many people will have heard about, <foreignObject>.

<foreignObject> and SVGs for the win!

This is the biggest trick to making things responsive.

You see, within a markdown file we are very limited as to what we can do (which is why we see people using <table> etc. for layouts...ewww).

But SVGs have a unique feature, <foreignObject>.

This allows you to include many things within an SVG, including HTML and CSS.

With that we have a lot more power!

You can see that in this demonstration CodePen (click the buttons to change the size of the outer container, which represents the available space on the page for the image):

CodePen Demo for CSS in SVG

Make sure to check out the html panel, all of the tricks are in there!

The key part of this is here:

 <svg xmlns="http://www.w3.org/2000/svg" fill="none">
        <foreignObject width="100%" height="100%"> 
            <div xmlns="http://www.w3.org/1999/xhtml">
                <!--we can include <style> elements, html elements etc. here now, with a few restrictions! Note it must be in xHTML style (so <img src="" /> not <img src="" > to be valid -->
            </div>
       </foreignObject>
</svg>
Enter fullscreen mode Exit fullscreen mode

From there we can use an inline <style> element and standard HTML elements to construct a responsive image.

But you may notice one other thing about the markup used in that demonstration.

The images gotchya!

There is a reason I have the images (both the SVG bubble and the image of me) as data URLs.

This is because of something called a Content Security Policy (CSP) and the way it is implemented on GitHub.

Now I won't explain CSPs, but in essence they have a rule that says "hey, no images can be loaded from anywhere other than the current context".

Not a problem for a normal image, but this is an image within an image and the "context" for that image is itself.

So if we try to include another image within our SVG it will come from a different place and break our SVG.

Luckily, data URIs are counted as the same context / origin.

So that is why they are used within our example and another thing to consider if you want to implement this yourself!

Last trick, the <picture> element and no whitespace.

I mean, this isn't even a trick!

The last 4 boxes in my readme are responsive (and honour colour preferences), but they use standard media queries to work.

The only consideration here was trying to find a break point that worked, which happened to be 768px on GitHub.

Then I created 4 sets of images:

  • dark mode and desktop
  • dark mode and mobile
  • light mode and desktop
  • light mode and mobile.

Large or small image

To get the right image we use media="(min-width: 769px) for desktop (large) image or media="max-width: 768px) for our mobile (small) image on each of the sources we put in our <picture> element.

Light and dark mode

To grab light or dark mode we use the prefers-color-scheme media query.

Combining our queries and sources

Then we just set up our <picture> element to pick the source that we want using a combination of (** width query **) and ( colour preference):

<picture>
  <source media="(min-width: 769px) and (prefers-color-scheme: light)" srcset="readme/light-tl@2x-100.jpg">

  <source media="(max-width: 768px) and (prefers-color-scheme: light)" srcset="readme/light-tlm@2x-100.jpg">

  <source media="(max-width: 768px) and (prefers-color-scheme: dark)" srcset="readme/dark-tlm@2x-100.jpg">

  <img src="readme/dark-tl@2x-100.jpg" alt="You will find me writing about tech, web dev, accessibility, breaking the internet and more over on DEV! Purple and neon pink design with Graham pointing at the next section" width="50%" title="My writing on DEV">
</picture>
Enter fullscreen mode Exit fullscreen mode

Not difficult as such, but time consuming creating 4 variations of images.

No white space

There was one last issue I had.

The bottom section is actually made up of 4 different images (yes, I had to create 16 different images for it...).

The reason for this is that each section is a clickable link.

Not complicated, but there is a small gotchya to be aware of.

If you want to have two images directly touch each other side by side (so both images are 50% width), you have to remove all white space between the anchors, the picture elements and even the sources inside those picture elements.

Otherwise GitHub will add some margin to your elements and they will not be on the same line.

Also, despite me removing all the white space I hit another limitation, there is still an 8px gap between the first row and second row that you cannot remove sadly (hence the line between!).

Wrapping up!

I may do some more in depth explanations of Content Security Policies, <picture> element tricks and, of course <foreignObject> in the future.

This was meant to be more of an introduction to the concepts so you could play with them yourself, not a tutorial.

But now that you know about the tricks I used I want to see you build a prettier GitHub readme than mine!

And if you do, please do share it in the comments! πŸ’ͺπŸΌπŸ™πŸΌπŸ’—

Happy coding everyone! πŸ’—

Top comments (46)

Collapse
 
cicirello profile image
Vincent A. Cicirello

You should submit your README to:

GitHub logo matiassingers / awesome-readme

A curated list of awesome READMEs

Awesome README Awesome

A curated list of awesome READMEs

Elements in beautiful READMEs include, but are not limited to: images, screenshots, GIFs, text formatting, etc.

Examples

  • ai/size-limit - Project logo, clear description, screenshot, step-by-step installing instructions.
  • aimeos/aimeos-typo3 - Project logo. Clear description of what the project does. Demo screenshot. TOC for easy navigation. Easy installation and setup sections with screenshots. Links for further reading.
  • ajeetdsouza/zoxide - Badges, project GIF, concise description, quick links, stepwise installation instructions.
  • alichtman/shallow-backup - Clear description of what the project does. GIF Demo. TOC for easy navigation. Badges. Links for further reading. Simple install instructions.
  • alichtman/stronghold - Project logo. Clear description of what the project does. GIF Demo. TOC for easy navigation. Badges. Links for further reading. Simple install instructions.
  • amitmerchant1990/electron-markdownify - Project logo. Minimalist description of what it is. GIF demo of the project. Key features. How to install guide. Credits.
  • amplication/amplication - Clear project logo…
Collapse
 
grahamthedev profile image
GrahamTheDev

Nice, I was going to submit it to the other repo that showcases readmes but it had like 425 issues. This one looks maintained, so thanks! πŸ™πŸΌπŸ’—

Collapse
 
cicirello profile image
Vincent A. Cicirello

You're welcome.

Collapse
 
arthurneuron profile image
Arthur Neuron

It looks fine πŸ‘πŸΎ, but for some reason one half is generated in a light style and the other half in a dark style.

Image description

Collapse
 
grahamthedev profile image
GrahamTheDev

Hmmmm, that looks like you have the theme set to dark directly in GitHub but the system setting is light mode maybe (and they do some weird trickery for light and dark mode on images)?

Darn, not sure how to fix that unless I use 2 different versions for the buttons and then use the <picture> element to fix.

I will have to have a fiddle, can I ask what browser (and if you have light mode as your system preference as I think?). Thanks for the bug report! πŸ€£πŸ™πŸΌπŸ’—

Collapse
 
arthurneuron profile image
Arthur Neuron • Edited

Safari Version 17.1.2 (19616.2.9.11.12)

I change the system theme, and the light version works fine.
When I change to the dark version, only the bottom half of the readme changes.

Image description

Thread Thread
 
grahamthedev profile image
GrahamTheDev • Edited

Ahhhh, it is the other problem, SVGs using embedded media queries for light mode preference don't work on Safari (actual iOS / MacOS issue) if you have dark mode enabled there!

I will fix that with 2 <picture> elements then, thanks for the heads up, never knew that restriction! πŸ™πŸΌπŸ’—

Collapse
 
taufik-h profile image
Taufik Hidayatulloh

use image with transparent background

Collapse
 
grahamthedev profile image
GrahamTheDev

Doesn’t work like that sadly as the colour scheme within the buttons needs to change for colour contrast. πŸ’—

Collapse
 
azasypkin profile image
Aleh Zasypkin • Edited

Very nice job @grahamthedev! Just one small correction:

This is because of something called a Content Security Policy (CSP) and the way it is implemented on GitHub.
Luckily, data URIs are counted as the same context / origin.

The data: URIs aren't considered the same context/origin (and will never be). It works because GitHub explicitly allows loading images using the data: protocol as the image source. I've imported the policy from your profile with Secutils.dev to illustrate (take a look at the Image source (img-src) field): "[Dev.To] GrahamTheDev's Profile" content security policy

The Image source (img-src) also shows that we have a few other options should GitHub remove data: from the allowed sources :)

Now I won't explain CSPs, but in essence they have a rule that says "hey, no images can be loaded from anywhere other than the current context".

And a shameless plug, if anyone likes to learn more about CSP, feel free to check out my other post on exploring web applications through their (CSP): dev.to/azasypkin/explore-web-appli...

Collapse
 
grahamthedev profile image
GrahamTheDev

Ahhhh, maybe that was raw.github.com that had the more restrictive policy (or maybe I just made it up lol).

I will try and have a dig around on Monday and will correct it!

Thanks! πŸ™πŸΌπŸ’—

Collapse
 
nickytonline profile image
Nick Taylor

Love this! Cool stuff Graham!

Yes, that's awesome!

Collapse
 
grahamthedev profile image
GrahamTheDev

Thanks bud! πŸ™πŸΌπŸ’—

Collapse
 
acontreras89 profile image
Aaron Contreras

To get rid of the vertical space between images, just set line-height to 0 in the wrapping div:

Image description

Collapse
 
grahamthedev profile image
GrahamTheDev

I don't think GitHub will allow you to that and it will get stripped (or is line-height an allowed style attribute they accept?).

Collapse
 
robole profile image
Rob OLeary • Edited

I had the same thought with SVGs on the profile readme! I just was not motivated to carve up images to demonstrate. Nice work!

Collapse
 
grahamthedev profile image
GrahamTheDev

Haha, don't blame you on that one, this took me hours to get right and working within all the restrictions! Better to just have a simple readme in the end lol! πŸ€£πŸ’—

Collapse
 
grahamthedev profile image
GrahamTheDev

If you have seen some beautiful GitHub readme's, please share them in the comments section, I would love to see them! πŸ’ͺπŸΌπŸ’—

Collapse
 
randellbrianknight profile image
Randell Brian Knight

This is so Cool. Thanks for sharing your insights, and I look forward to more posts about these topics.

Collapse
 
tharakamts profile image
Tharaka Sandaruwan

Nice work πŸ”₯

Collapse
 
it0dan profile image
D.aΘ 

Awesome!!

Some comments may only be visible to logged-in visitors. Sign in to view all comments.