Responsive design with SVG & CSS
Eduardo Cookie Lifter
Posted on March 12, 2021
Today I want to show you something very cool that I think you're gonna like and this is mostly about designing with CSS and what it essentially does is to use an SVG and depending on the breakpoint we can pick and choose what elements we will show to the user, it's very simple and at the same time it's very powerful to companies. So for example if you are working on a site, and you have a logo buuuut you have 2, 3 or even 4 variations and don't know which one to use, what if there was a way to show all of them?
With CSS it's possible and im gonna show you a way how to do this, the concept of "responsive design" works like this:
- You have a logo with 1 or 2 variations and this typically means that your logo either has black color applied when it will be shown on white backgrounds and viceversa, this is one of the many situations where you might want to reach for an alternative design on a logo, or say you already have a logo and the background color is not that important, but you just want to show a portion of it when it's viewed on larger screen sizes because as you might've guessed, it doesn't really matters if you show a circle that goes in the background of your logo, or any shape for that matter.
Using media queries can help you choose which elements to hide or show. Ok so let's begin.
Majik Whistle, because they don't make like this no more!
SVG workflow
Ok so the first thing we're gonna need is to have our SVG logo, for this example I made up my own using Adobe Illustrator but any program that can save SVG's such as Corel Draw or Gimp we just care about the SVG. In Illustrator you can copy your vectors by just selecting everything and hitting Cmd + C or if you're on Windows Ctrl + C. Alternatively, what you can do is to save your file because what we are going to be working on with next, is SVGO. In here we can paste our SVG markup or upload a file, I think this tool is pretty awesome because it will give you a compiled SVG format which you can then later use on your HTML and that's what we want to do.
After you're done copying or uploading what you're gonna want to do next is to copy the newly rendered markup by clicking on the icon that has 2 squares, below the paint bucker and above the turquoise-color-button, it should be at the bottom of the page next to the all of the options SVGO can do for you, and this panel is where you can toggle on and off whatever you want to include in your markup, so for example if you want to add the viewBox property this is where can search for it and toggle (by default it's not included which I think it's pretty rare but that's okay)
Next
Okay, so we got our SVG markup on our HTML and so the last thing we need is to define our media queries and the way we're gonna handle this is NOT by creating a CSS file, we are going to be writing CSS but this time it's not going to be on a separate file we are simply going to handle all the breakpoints inside the SVG element, after that we will hide and show what we want, it's up to us.
So you probably have something like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
Now all you need to do is to style your content, for this im gonna use TailwindCSS which is a utility first CSS framework which means it uses Javascript to render classes I think it's really neat im using it all the time now, it's one of those things that get me on the edge, it lets me focus on the design and if im writing server side logic I now don't have to spend any time trying to organize my naming conventions for all of my CSS classes, however since we are going to be writing CSS inside the SVG we might reach for Tailwind only for the containers, wrappers and it will be for alignment purpouses only, we are also going to be making use of the Tailwinds breakpoints as a point of reference to determine what are going to be some of the elements inside our logo that we're gonna be working with.
Awesome, let's begin!
Just HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
</head>
<div class="bg-gray-600 h-full flex flex-col md:grid md:grid-cols-8 w-screen h-screen">
<div class="md:col-span-3 p-4 text-white flex items-center justify-center flex-col">
<ol class="list-decimal pl-6">
<li class="md:mb-20 mb-0 font-mono">We can change the look of our logo by being explicit in the CSS Media Queries.</li>
<li class="md:mb-20 mb-0 font-mono">We can show as much or as little as we want, it's up to us.</li>
<li class="md:mb-20 mb-0 font-mono">It's all done by using SVG, CSS elements, media queries and nothing else.</li>
</ol>
</div>
<div class="h-full bg-white md:col-span-5 p-4 flex items-center justify-center text-white">
<div class="mt-10 md:mt-0 container mx-auto lg:border-4 lg:border-purple-500 lg:bg-white md:border-4 md:border-yellow-500 md:bg-gray-900 sm:border-4 sm:border-red-500 border-4 border-green-500 rounded-md">
</div>
</div>
</div>
Ok, this is all of the Tailwind we're going to use, you're more than welcome to use the same style but if you prefer you can of course use your own layout or if you want you can use CSS it doesn't matter, we just want to give our logo enough space so we can know what's up with it, also im just using a sidebar to provide some insight into the final outcome, it's just an organized list with 3 bullet points or the most important things we can get out of from responsive design. Im gonna go over the classes really quick and then we will be able to start constructing the ins and outs of each breakpoints.
We need a "general" wrapper, container call it what you want but essentially what we are going to be building to display our logo and the list are: a sidebar and we're gonna most of the space to the logo, so that's 3 columns for the sidebar and 5 for the SVG.
As you can see I've used flexbox for my mobile layout and when the screen is at larger screens we're gonna be using CSS Grid, which I think it's pretty awesome. We're gonna style it very simple with a gray background. Tailwind color classes are pretty cool, in fact if you decide you want your own custom palette you can do that in tailwind.config.js and do any change you want but that is out of the scope for this article so we're gonna stick to our 8 column layout.
For the height and width of the layout I will be using the full screen as my parameter so it's going to take over the whole screen, the whole width and height of the screen, that should set us up with a basic and simple looking 2 column layout.
The Main Layout
As you know, our layout doesn't exactly has 2 columns not even close, we want 8 columns im going to show later on why.
<div class="w-screen h-screen bg-gray-600 flex flex-col md:grid md:grid-cols-8">
<!-- add content here -->
</div>
Next, we need to define the sidebar, ok so let's do that:
<div class="bg-gray-600 flex flex-col md:grid md:grid-cols-8 w-screen h-screen">
<div class="md:col-span-3 p-4 text-white flex items-center justify-center flex-col">
<!-- we should add something here -->
</div> <!-- 3 column wrapper ends -->
</div> <!-- main layout -->
Okay, by now you should have 3 column from your left to right side, what we need to do next is to define the following 5 columns:
<div class="bg-gray-600 flex flex-col md:grid md:grid-cols-8 w-screen h-screen">
<div class="md:col-span-3 p-4 text-white flex items-center justify-center flex-col">
<!-- organized list goes here -->
</div> <!-- 3 column wrapper ends -->
<div class="h-full bg-white md:col-span-5 p-4 flex items-center justify-center text-white">
</div> <!-- 5 column wrapper ends -->
</div> <!-- the main layout ends -->
Tailwind
Like I mentioned earlier we are going to be displaying 2 columns but in fact what we really have are 8 columns only that we are going to span them across the entire screen, starting from the left with 3 columns and once it reaches column number 3, we are going to create a new div that will now take over the remaining space of the screen, and that is 5 columns.
Earler efined that we wanted 8 columns only on our medium breakpoint:
md:grid md:grid-cols-8
all we had to do after was to decide how we would be splitting them, and that is 3 starting from the left, and once that reaches the limit, we create another div and we let that one have the most space of the screen, pretty simple right? Yea as you can see we added a flex behaviour to our sidebar and what that means is that we are going to set a flex column that is going to align our content at the center and Tailwind provides with those classes, by using;
items-center
we are basically saying:
align-items: center;
and when we provide to our div element:
justify-content: center
we are letting the browser know that what we want is to have a column with our content centered, from top to bottom and left to right,
justify-center
does that for us.
For the remaining space of the layout, which will be where our SVG will be, we are going to repeat the same process we are going to need a flexbox only that this time we are going to skip the column and just stick with a simple row, that's all we want, we are just displaying the logo and nothing else.
Because we want our logo to occupy the full height of the screen for all screen sizes we defined h-full and that's all we need. If you want you can add a background color in this area, it's just so we are aware of the division it really doesn't matter. I think it's a reminder of the space we have for each space, it lets us know that there is a separation on our items this is important to know when you have different elements and both of them are as equally important, by defining a width and a color to each you're basically saying "both are important" or "you should look at both", of course you don't want to over do it and assign the minimum space to a sidebar just because it's just text, no, you want to give each section the right amount of importance.
SVG & Media queries, but first..
Moving on, now we are going to finally build the SVG with all the media queries required for this little demo project. First, inside the SVG element we will be adding a couple of Tailwind classes and then we can move on to build the neccessary CSS that will allow us to toggle portions of the logo depending on the breakpoint of the screen, very simple we are just going to add 2 classes in the SVG element, we are going to say we want some padding and that we want the content to be centered like this:
class="mx-auto pt-4"
That is all we need for the SVG element in our little project, next thing will be to toggle the visibility of the components of the logo when the screen hits a certain breakpoint and this is done with CSS Media queries and CSS properties, more especifically we will make use of the opacity property and fill because as it turns out sometimes you don't want to hide or show an element but change the way it looks because often times when a client hands you a logo they might give you 2 images, one that is only used when there is a dark background and one where there's a white background and for this case we don't want to hide but we just want to change the fill value. Let's write our first media query, let me show you how my SVG markup looks like, remember we copied and pasted the markup from SVGO? For the wrapper or the container we are going to be inserting a couple of Tailwind classes in a div and we will add these after the wrapper of the organized list inside the wrapper we previously created.
<div class="bg-gray-600 flex flex-col md:grid md:grid-cols-8 w-screen h-screen">
<div class="md:col-span-3 p-4 text-white flex items-center justify-center flex-col">
<!-- this is where the organized list goes -->
</div> <!-- 3 column wrapper ends -->
<div class="h-full md:col-span-5 p-4 flex items-center justify-center text-white">
<div class="mt-10 md:mt-0 container mx-auto lg:border-4 lg:border-purple-500 lg:bg-white md:border-4 md:border-yellow-500 md:bg-gray-900 sm:border-4 sm:border-red-500 border-4 border-green-500 rounded-md">
<!-- this is where we will paste the SVG markup -->
</div> <!-- svg wrapper ends here -->
</div> <!-- 5 column wrapper ends -->
</div> <!-- the main layout ends -->
Come join the SVG!
Let's begin by adding the markup now.
<div class="mt-10 md:mt-0 container mx-auto lg:border-4 lg:border-purple-500 lg:bg-white md:border-4 md:border-yellow-500 md:bg-gray-900 sm:border-4 sm:border-red-500 border-4 border-green-500 rounded-md">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 330 377"
class="mx-auto pt-4"
>
<style>
.st3{fill:#333}
.st4{fill:#040006}
.st6{fill:#fff}
svg * {
transition: fill .1s ease-out, opacity .1s ease-out;
}
@media all and (min-width: 320px) {
svg {
width: 144px;
}
#orange-circle {
opacity: 0;
}
#whistle-inner {
opacity: 1;
}
.st3 {
fill: #040006;
}
}
@media all and (min-width: 640px) {
svg {
width: 144px;
}
.st3 {
fill: #fff;
}
.st6 {
fill: #000000;
}
}
@media all and (min-width: 768px) {
svg {
width: 89px;
}
#purple-circle {
opacity: 0;
}
.st6 {
fill: #fff;
}
.st4 {
fill: gainsboro;
}
} <!-- md -->
@media all and (min-width: 1024px) {
svg {
width: 377px;
}
#orange-circle, #purple-circle {
opacity: 1;
}
.st6 {
fill: #fff;
}
.st3 {
fill: #333;
}
.st4 {
fill: #040006;
}
} <!-- lg -->
</style>
<!-- purple -->
<circle cx="161.7" cy="140.2" r="140.2" fill="#63c" id="purple-circle"/>
<!-- orange -->
<circle cx="147.8" cy="150.7" r="114.7" fill="#f93" id="orange-circle"/>
<g opacity=".55" id="whistle-inner">
<path
class="st3"
d="M61.6 167.4c.6 9.4-6.8 17.1-16 17.1v-32.1h1c8 .5 14.5 7 15 15z"
/> <!-- whistle inner dot -->
<path
class="st3"
d="M45.5 198.3c17.1 0 30.9-14.4 29.8-31.8-.9-14.9-13-27-27.9-27.9h-1.9v-12.5c27.2 0 51.8 14.9 69.9 39 1.5 2 1.5 4.7 0 6.7-18.2 24.2-42.8 39-69.9 39v-12.5z"
/> <!-- whistle smooth curve -->
</g> <!-- eye -->
<g id="isotype">
<path
class="st4"
d="M35.8 239.2l-4.2 19 18.1-7.2 8.9 7.6-26.9 31.6-8.9-7.6L33.5 270l-18.1 7.2 4.2-19-10.7 12.6-8.9-7.6 26.9-31.6 8.9 7.6zM69.9 263.6l-5.8 45.2-11.2-6.4.7-4.4-5.2-3-3.4 2.9-11.2-6.4 36.1-27.9zm-13.7 26.5l.9-4.3-3.2 3 2.3 1.3zM81 308.9c-.7 1.7-1.6 3.2-2.8 4.5-1.1 1.3-2.4 2.3-3.8 2.9l-10.5-4.4c1.4-.6 2.7-1.6 3.8-2.9s2.1-2.8 2.8-4.5l13.8-32.9 10.5 4.4L81 308.9zM93.9 319.6l-11.1-3.7L96 276.5l11.1 3.7-13.2 39.4zM138.7 287.2l-12.5 15.5 3.9 25.1-12.3-2.5-1.6-10.2-6.8 8.5-10.2-2.1 8.3-40.7 11.4 2.3-2.7 13.3 9.6-11.8 12.9 2.6zM173.2 287.2l12.9-.3-10 42.3-12-13-11.3 13.7-12.3-41.7 12.9-.4 4.7 18.6 5.5-8.3 6 8 3.6-18.9z"
/> <!-- "MAJIK W" -->
<path
class="st4"
d="M205.2 324l-3.1-14.6-3.1.7 3.1 14.6-11.4 2.4-8.5-40.6 11.4-2.4 3.1 14.6 3.1-.7-3.1-14.6 11.4-2.4 8.5 40.6-11.4 2.4zM232.8 316.2l-11.1 3.7-13-39.4 11.2-3.7 12.9 39.4zM255.7 291c1.7 3.7 1.9 7.4.7 11.1-1.2 3.7-3.8 6.4-7.7 8.2-3 1.3-6 1.7-9.1 1.2s-5.7-1.8-7.8-4l7.9-8.8c1.3 1.1 2.6 1.4 3.8.9.7-.3 1.2-.9 1.4-1.6.2-.7.2-1.5-.1-2.2-.3-.6-.8-1-1.5-1.3s-1.8-.2-3.2 0c-3 .6-5.9.3-8.7-.7-2.8-1-4.9-3.1-6.3-6.2s-1.6-6.3-.4-9.4c1.1-3.1 3.2-5.4 6.3-6.8 1.6-.7 3.2-1.1 4.8-1.1 1.6 0 2.8.1 3.7.5l-2.7 12.1c5-1.1 9.1-.8 12.2 1 3.1 1.7 5.4 4.1 6.7 7.1z"
/> <!-- "HIS" -->
<path
class="st4"
d="M265.9 301l-15.3-25.6-6.9 4.1-6-10.1 23.8-14.2 6 10.1-6.9 4.1 15.3 25.6-10 6z"
/> <!-- "T" -->
<path
class="st4"
d="M288.4 271.6l8-6.3 7.3 9.2-17.1 13.5-25.8-32.6 9.2-7.2 18.4 23.4zM294 242.3l2.2 2.2 7.7-7.8 8.3 8.2-7.7 7.8 2.3 2.2 7.7-7.8 8.4 8.2-15.9 16.1-29.7-29 15.9-16.1 8.4 8.2-7.6 7.8z"
/> <!-- "LE" -->
</g> <!-- "MAJIK WHISTLE" -->
<g id="whistle">
<path
d="M269.5 170.1l-42.2-21.2c-1.9-.9-4-1.1-6-.5l-18 6-18.2-9.2 3.5-7c2-3.9.4-8.6-3.5-10.6l-63.3-31.9c-38.8-19.5-86.2-3.8-105.7 35s-3.8 86.2 35 105.7c34.8 17.5 76.6 7.1 99.2-24.1l97.5 7.8c3.2.3 6.2-1.5 7.7-4.3l17.7-35.2c1.7-3.8.1-8.5-3.7-10.5zM68.6 201.3c-19.4-9.8-27.3-33.4-17.5-52.9 9.8-19.4 33.4-27.3 52.9-17.5 19.4 9.8 27.3 33.4 17.5 52.9S88 211.1 68.6 201.3z"
fill="#0c6"
/> <!-- whistle -->
</g>
<g id="white-stripes">
<g>
<path
class="st6"
d="M241.5 67.9c-3.9-2-8.6-.4-10.6 3.5l-21.2 42.2c-2 3.9-.4 8.6 3.5 10.6s8.6.4 10.6-3.5L245 78.5c2-3.9.4-8.6-3.5-10.6z"
/> <!-- 1 -->
</g>
<g>
<path
class="st6"
d="M196.4 101.6l-7-38.8c-.8-4.3-4.9-7.1-9.1-6.4-4.3.8-7.1 4.9-6.4 9.1l7 38.8c.5 2.5 2.1 4.6 4.2 5.6 1.5.7 3.2 1 4.9.7 4.3-.6 7.1-4.7 6.4-9z"
/> <!-- 2 -->
</g>
<g>
<path
class="st6"
d="M287.2 110.3c-1.9-3.9-6.6-5.5-10.6-3.5l-35.2 17.5c-3.9 1.9-5.5 6.7-3.5 10.6.8 1.6 2.1 2.8 3.5 3.5 2.1 1.1 4.7 1.2 7 0l35.3-17.5c3.8-2 5.4-6.7 3.5-10.6z"
/> <!-- 3 -->
</g>
</g> <!-- the white stripes -->
</svg>
</div>
It might look like a lot but don't worry we are just going to be focusing on the part where we can add CSS and that is below
the tag, and by default that is always included after SVG is initialized so let's focus our attention there and begin setting some properties, one thing before doing that, note that by default Adobe Illustrator exports certains classes and this is done by default we will use those classes whenever we want to change the fill of an element in the logo, for the cases where we might want to set a given opacity number we will target the ids of the
Transition effect
<style>
svg * {
transition: fill .1s ease-out, opacity .1s ease-out;
}
Media queries, you made it this far
What we want to do first is to target all the SVG elements in the page and set 2 properties, and for this demo we're just going to tell the browser whenever there is a change in opacity, we want to add a transition property to it and it should take 1 second to complete, and it should ease out.
After that let's add Media Queries and i'll be going 1 by 1. So Tailwind has responsive classes set to a specific breakpoints, for the first one we're not going to be targeting that instead what we are going to do is target the iPhone breakpoint that Firefox comes by default and that is a 320px resolution screen:
@media all and (min-width: 320px) {
svg {
width: 144px;
}
#orange-circle {
opacity: 0;
}
#whistle-inner {
opacity: 1;
}
.st3 {
fill: #040006;
}
} <!-- firefox iPhone 5 width resolution -->
Okay so as you see, and we are going to be doing this over again for all of our screen breakpoints, we are simply going to set opacity to 0 or 1, depending on what we want to do and change the fill property of an element if that's what the logo requires, we are going to repeat this process for every single breakpoint, and for that we are going to be using the Tailwind responsive classes and we are just going to be using sm md and lg, Tailwind has many more but for the purpouses of this tutorial that's all we are going to stick with.
Let's hit all of the breakpoints!
sm
@media all and (min-width: 640px) {
svg {
width: 144px;
}
.st3 {
fill: #fff;
}
.st6 {
fill: #000000;
}
} <!-- sm -->
md
@media all and (min-width: 768px) {
svg {
width: 89px;
}
#purple-circle {
opacity: 0;
}
.st6 {
fill: #fff;
}
.st4 {
fill: gainsboro;
}
} <!-- md -->
lg
@media all and (min-width: 1024px) {
svg {
width: 377px;
}
#orange-circle, #purple-circle {
opacity: 1;
}
.st6 {
fill: #fff;
}
.st3 {
fill: #333;
}
.st4 {
fill: #040006;
}
} <!-- lg -->
Wrapping up
Just one more time, whenever we want to change the color of an element inside our logo we are going to be targetting the default SVG class that it comes with from Illustrator, if we want to change the visibility, we're gonna be using the id of the element and as you can see I've added one for every single group there is in this markup.
Im gonna leave a Codepen for you to check it out and play with it, im also gonna leave you a link with a "progression chart" where you can see how it evolves from each breakpoint.
https://codepen.io/pen/?template=gOLZyMJ
View post on imgur.com
Posted on March 12, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.