Search code examples
androidcssiphoneipadmedia-queries

Feedback on Universal CSS Media Queries


I have created a template that I hope can be of use to you in clarifying a few things for me regarding media queries. There are so many slightly different versions out there that perhaps I can narrow it down to just what I need.

Basically my question is, looking at what I have, do I need to be even more specific about the target device? For example, and iPad Standard or an iPad Retina, and if it's either and on landscape or portrait, pixel ratio of either... man... Lots of examples online date back a few years.

Here's a live link

Test Page

Ctrl + Shift + M to play around with mobile screen sizes..

Here's a full stand alone working version since we need a full browser tab to expand and shrink during testing.

I have commented the code and the output as well so that you can explain it to me as you expand and shrink the browser window in real time.

<!DOCTYPE html>
<html>

<head>
<title>v6</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 1. BOOTSTRAP v4.0.0         CSS !-->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<!-- 2. FONT AWESOME v4.7.0      CSS !-->
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous" async="" defer="">
<!-- 2.1 Google Material Icons   CSS !-->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!-- 3. GOOGLE JQUERY JS v3.2.1  JS !-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!-- 4. POPPER v1.12.9           JS !-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<!-- 5. BOOTSTRAP v4.0.0         JS !-->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<style>

/* STATIC CSS */

body {
background-color: #fbf1c7;
} 

.progress-path-lg {
background-color: gainsboro;

}

.progress-step-lg {
border-bottom: 4px solid silver;
opacity: 0.5;
}

.progress-step-lg-active {
border-bottom: 4px solid dodgerblue;
opacity: 1;
}

.progress-step-lg-number {
font-size: 2.5rem;
font-weight: 400;
}

.progress-step-lg-label {
font-size: 1.25rem;
font-weight: 400;
}

#output:before {
display:block;
white-space: pre;
content: "► Color: Default \A Device: N/A \A Orientation: N/A \A Begins @ 0px \A Range: 0px > 319px";

}

/* 

Media query Screen Width Logic

*** This is the stuff I'm learning right now... ***

1. Default CSS styles above are assumed UNTIL the first media query condition is met.
2. Conditions cascade upwards triggering at their respective Pixel landmark.

*/

@media only screen 
and (min-width:320px) { 
    /* smartphones, portrait iPhone, portrait 480x320 phones (Android) */ 
    body { background-color: #fb4934; } 
    #output:before {
        display:block;
        white-space: pre;
        content: "► Color: Red \A ► Device: smartphones, portrait iPhone, \A portrait 480x320 phones (Android) \A ► Orientation: N/A \A ► Begins @ 320px \A ► Range: 320px > 479px";

    }
}



@media only screen 
and (min-width:480px) { 
    /* smartphones, Android phones, landscape iPhone */ 
    body { background-color: #b8bb26; } 
    #output:before {
        display:block;
        white-space: pre;
        content: "► Color: Green \A ► Device: smartphones, Android phones, \A landscape iPhone \A ► Orientation: N/A \A ► Begins @ 480px \A ► Range: 480px > 599px";
    }
}



@media only screen 
and (min-width:600px) { 
    /* portrait tablets, portrait iPad, e-readers (Nook/Kindle), landscape 800x480 phones (Android) */ 
    body { background-color: #fabd2f; } 
    #output:before {
        display:block;
        white-space: pre;
        content: "► Color: Yellow \A ► Device: portrait tablets, portrait iPad, e-readers (Nook/Kindle), \A landscape 800x480 phones (Android) \A ► Orientation: N/A \A ► Begins @ 600px \A ► Range: 600px > 800px";

    }
}



@media only screen 
and (min-width:801px) { 
    /* tablet, landscape iPad, lo-res laptops ands desktops */ 
    body { background-color: #83a598; } 
    #output:before {
        display:block;
        white-space: pre;
        content: "► Color: Blue \A ► Device: tablet, landscape iPad, lo-res laptops ands desktops \A ► Orientation: N/A \A ► Begins @ 801px \A ► Range: 801px > 1024px";
    }
}



@media only screen 
and (min-width:1025px) { 
    /* big landscape tablets, laptops, and desktops */ 
    body { background-color: #d3869b; } 
    #output:before {
        display:block;
        white-space: pre;
        content: "► Color: Purple \A ► Device: big landscape tablets, laptops, and desktops \A ► Orientation: N/A \A ► Begins @ 1025px \A ► Range: 1025px > 1280px";

    }
}



@media only screen 
and (min-width:1281px) { 
    /* hi-res laptops and desktops */ 
    body { background-color: #8ec07c; } 
    #output:before {
        display:block;
        white-space: pre;
        content: "► Color: Aqua \A ► Device: hi-res laptops and desktops \A ► Orientation: N/A \A ► Begins @ 1281px \A ► Range: 1281px > infinity";

    }
}

</style>
</head>

<body>
<!-- BEGIN WRAPPER !-->
<div class="py-5">
<!-- BEGIN CONTAINER !-->
<div class="container">



<!-- BEGIN PROGRESS PATH !-->
<!-- BEGIN ROW !-->
<div class="row progress-path-lg">

<!-- NEW COLUMN - SIZE 3 !-->
<div class="col-3 d-flex progress-step-lg">
<span class="progress-step-lg-number">1</span>
<span class="progress-step-lg-label px-2 pt-3">Step</span>
</div>
<!-- NEW COLUMN - SIZE 3 !-->
<div class="col-3 d-flex progress-step-lg-active">
<span class="progress-step-lg-number">2</span>
<span class="progress-step-lg-label px-2 pt-3">Step</span>
</div>
<!-- NEW COLUMN - SIZE 3 !-->
<div class="col-3 d-flex progress-step-lg">
<span class="progress-step-lg-number">3</span> 
<span class="progress-step-lg-label px-2 pt-3">Step</span>
</div>
<!-- NEW COLUMN - SIZE 3 !-->
<div class="col-3 d-flex progress-step-lg"> 
<span class="progress-step-lg-number">4</span>
<span class="progress-step-lg-label px-2 pt-3">Step</span>
</div>

</div>
<!-- END ROW !-->
<!-- END PROGRESS PATH !-->



<hr>



<!-- BEGIN ROW !-->
<div class="row">
<!-- CSS CONTENT OUTPUT CONTAINER !-->
<div class="col-12" id="output"></div>

</div>
<!-- END ROW !-->
</div>



<hr>



<!-- END CONTAINER !-->
</div>
<!-- END WRAPPER !-->
</body>

</html>

Solution

  • Trying to determine device (based on page width) is ultimately wrong. In principle, you shouldn't need it. In reality, you might need to, but as you already noticed, it's nearly impossible, as a device can and will be used in both landscape and portrait mode, rendering your efforts pretty much useless. Besides, there are too many models out there and when you combine them with browsers, you've got a lot of media queries to write.

    So the answer to your question is "No, you don't need to be more specific. If you find yourself needing to determine the device, you should change your code so you don't need this piece of information." (i.e.: find polyfills for what you use, to extend browser support).

    You should stick to what seems to work well for the rest of the world, which is mobile-first principle:

    • style your page for all devices, including the smallest of mobile phones
    • add special rules (if any) for small mobile phones, usually above 319px
    • add special rules (if any) for normal mobile phones, usually above 480px
    • add special rules (if any) for large mobile phones, tablets and tiny desktops, usually above 767px;
    • add special rules (if any) for large tablets and small desktops, usually above 991px;
    • add special rules for normal desktops, usually above 1199px
    • add special rules for extra large desktops, usually above 1499px

    Please note the custom 768px and 992px do not come from Bootstrap, although Bootstrap v3 uses them. They have been determined based on common widths of screens on various devices. You should always keep an eye at what Bootstrap or other commonly used libraries have, as they put a lot of effort into making sane decisions. So, if you're not keen on putting the research hours into it, you're better off just trusting them. (For example, it's likely Bootstrap v4 will use different breakpoints, as devices usage changes and v5 to have other breakpoints and so on...).

    If coded right, you should never need to code in rules for extra large desktops, nor should you need to specify any combos of (min-width:*px) and (max-width:*px). Of course, within reasonable limits.


    In theory, the above should be enough. In reality, in some particular cases you might need to do stuff (apply patches) on some weird device + browser combo. There are lightweight JavaScript solutions to help you discover the device as fast as possible and take appropriate action. The principle is:

    • load as little CSS as possible (minimal for above the fold)
    • let CSSOM get built fast so you can run js
    • run JS to determine device -> take appropriate action
    • load the rest of your CSS async (which rebuilds CSSOM when loaded - ideally without FOUC)
    • run rest of your JS (do note the bulk of your JS will have to be set to run on a custom event, triggered when async CSS has loaded, most likely after window.load event).

    Last, but not least, what I outlined above is not normally necessary on a regular website. It's a pretty high-end customization, typically expensive and only considered by big guys, with a lot of traffic, for whom rendering the page a second faster is really important, so they're willing to pay the development costs.

    On another note, what makes the above technique be way too expensive and over the top for normal folks is it requires considerable effort for splitting the CSS but it only impacts the initial page load. Subsequent page loads (when CSS is cached) will be just as fast on websites not implementing the above as on websites implementing it.


    If you're really interested in the subject, you probably want to subscribe to Chrome dev tools feed. You'll find a lot of interesting talks about web performance, and tools to measure it.