#media query to differentiate mobile from tablet - html

For multiple years I've been using min-device-width or max-device-width to differentiate mobile from tablet. Mobile CSS moves the cascading navigation menu to the bottom of the page, and simplifies the styling for readability. Tablet CSS leaves the page styling alone, as the screen size is sufficient to not require simplification. I have only iOS devices to test with. It works, but both min-device-width and max-device-width are deprecated in CSS and I am trying to move to #media to continue serving different CSS to both devices.
Where I am falling down is finding a clean method of doing so. My hope was that I could use some query like hover: none or pointer: coarse to detect one platform vs. the other, but iPhone and iPad both show as no hover, coarse pointer. My second attempt was to couple these queries with screen width query, but that has been a mess. Apple documentation shows native portrait-mode screen widths for recent iOS devices to be 640 to 1125px width for iPhones, and 1536 to 2224px for iPads. However, querying width in JS on my phone comes up with numbers that seem to instead match the UIKit widths (320-414px). Using a CSS #media (max-width: 450px) should match a phone, but it doesn't - it seems that the CSS is reading the native resolution width but JS is reading the scaled width. To get an element to only show up on my own iPhone I need to set max-width to something like 999px, but if it's truly reporting native resolution this would fail on an iPhone Plus - my phone is on the lower end of the screen size.
This seems pretty ridiculous. Is there a better way to serve one set of CSS rules to a mobile and another to a tablet, without having to set 37 different potential screen shape entries or use deprecated elements? I really don't want to have to rewrite my CSS every time a new phone model is released, or resort to browser sniffing - the less scripting running on the backend just for basic page display the better.
Per request: My really simple test file:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
<meta charset="utf-8" />
<script>
window.onload = function(){
var devpxratio = window.devicePixelRatio;
var devwidth = screen.width;
document.getElementById('ratio').innerHTML = devpxratio;
document.getElementById('wide').innerHTML = devwidth;
};
</script>
<style type="text/css">
.mobile, .tablet, .desktop, .touch, .hover, .fine, .phone {
display: none;
}
#media (hover: none) {
.mobile { /* show all mobile-specific content */
display: block;
}
}
#media (pointer: coarse) {
.touch { /* show touch-only content */
display: block;
}
}
#media (hover: hover) {
.hover { /* show hover-capable content */
display: block;
}
}
#media (pointer: fine) {
.fine { /* show fine pointer content */
display: block;
}
}
#media (hover: none) and (max-width: 375px) {
.phone { /* guessing at mobile vs tablet based on width */
display: block;
}
}
#media (hover: none) and (min-width: 1000px) {
.tablet { /* guessing at mobile vs tablet based on width */
display: block;
}
}
#media (hover: hover) and (pointer: fine) {
.desktop { /* show stuff that would be visible on desktop */
display: block;
}
}
</style>
</head>
<body>
<p>Device pixel ratio: <span id="ratio"></span></p>
<p>Device width: <span id="wide"></span></p>
<p class="mobile">No hover detected</p>
<p class="touch">Coarse pointer detected</p>
<p class="hover">Hover detected</p>
<p class="fine">Fine pointer detected</p>
<p class="phone">This is likely a phone</p>
<p class="tablet">This is likely a tablet</p>
<p class="desktop">This is likely a desktop</p>
</body>
</html>
Expected outcome on my iPhone is:
Device pixel ratio: 2
Device width: 375
No hover detected
Coarse pointer detected
This is likely a phone.
Actual output is:
Device pixel ratio: 2
Device width: 375
No hover detected
Coarse pointer detected
I can't get it to output "likely a phone" unless my specified max-width is 980px or higher. None of the results seem to make any logical sense. Javascript check for screen width tells me 375px, which matches expected screen width for my phone (second generation iPhone SE, which uses same screen as iPhone 8). Apple documentation states native resolution of an iPhone SE is 750px with a UIKit width of 375pt. I cannot find any math whatsoever to tell me why the numbers come out as they do. 375pt should be 500px, not 375; there's no logic to why the calculated screen size doesn't match the screen size used by CSS in the test page, and I cannot make heads or tails out of why any of the screen size numbers can relate to a CSS width of not more than 980px, unless the scaling factor is being reported incorrectly - it shows as 2, but scaling of 2.6 would result in a 375px screen equating to 980px. Again, especially with manufacturer specs, determining the screen size break points should not be this difficult...

Usual practice for responsive design is to address just several groups of devices defined by max. viewport width, so you don't need to fiddle with every possible screen size individually. As an example you can start with these:
https://www.w3schools.com/howto/howto_css_media_query_breakpoints.asp
Anyway CSS #media (max-width: 450px) should definitely match the phone of 320-414px screen size (since 320 < 450)... Could you please show us some code where it does not work for you?

Related

Bug with browsers' interpretation of #media queries

There was a question related to this one a long time ago, but which was never responded to or resolved.
I am developing a web site that has distinct screen layouts, which depend upon the width of the viewport/window.
#media (min-width: 1120px) { }
/* behaviour as expected */
#media (min-width: 720px) and (max-width: 1119px) { }
/* inconsistent behaviour in Firefox and Edge, mixing elements of above and below */
#media (max-width: 719px) { }
In my browser of preference, Chrome, the layouts transition perfectly from the largest screen width to the smallest. The same is true of Opera. However, both Firefox and Edge demonstrate a strange behaviour whereby a single transitional width (of one pixel) causes the browser not to know how to interpret the content.
For example, as the window transitions to the narrowest media width, the title bar becomes narrower, no longer being required to accommodate the main menu, and the menu is hidden (display: none;) and replaced by a small menu icon at the side, which leads to a drop down on hover. But in Firefox and Edge, the main menu is not hidden, but instead crammed beside the logo until the window is collapsed one pixel further, after which the behaviour is as expected. These CSS changes are all under the same #media declaration!
Interestingly, the behaviour is not consistent. That is, the transition from the largest to the middle width is flawless, but the transition from the middle to the smallest is problematic.
Assuming that it was an issue with fractional size calculations, I added high precision to my #media query like this:
#media (max-width: 719.999px)
And again, the behaviour was inconsistent. If I adjusted the lower value up (i.e. 719px to 719.999px) there was no change. However, if I instead adjusted the higher value down (i.e. 720px to 719.001px) the problem was partially solved. Certain elements displayed expected behaviour, but again, other anomalies persisted. Similarly, the higher precision worked on Firefox but not Edge.
It seems probable, given the behaviour that I am seeing, that certain boundaries might cause problems, whilst others would not.
Is this just a known bug that web site developers have learnt to accept, or might there be an easy solution (other than simply selecting a different set of boundaries)?
It's difficult to give a specific answer without seeing what you are seeing, but it's possible that the browsers are handling the transition from one media query to the next in different ways discussed below.
Most Likely Cause: Windows Display Settings
I assume you are using Windows when you mention Edge, I suspect this might be because you have changed the scale of your display in Windows - Display Settings. If this is set to 125% for example, this can have an affect on all aspects of your display.
So really this isn't a bug with the media queries, so much as a discrepancy caused by the browsers not effectively handling the scaling by Windows Display settings.
UPDATE - Now that you have confirmed that you can stop on a particular point where this happens, then I'm pretty confident this is the cause. In my testing yesterday when looking into this, I was able to reproduce that behaviour when the display was scaled.
Using the following test case with original styling of an empty block with a red border, and different CSS applied at (max-width: 1119px) and (min-width: 1120px), the issue happens only when the display is scaled.
body{ margin:50px 0 0 0;}
.test {
border: 10px solid #f00;
height: 10px;
}
#media (min-width: 1120px) {
.test {
background: #ff0;
height: 500px
}
}
#media (min-width: 720px) and (max-width: 1119px) {
.test {
margin-left: 300px;
background: #0FF;
height: 200px
}
}
#media (min-width: 460px) and (max-width: 719px) {
.test {
margin-left: 300px;
background: #00f;
height: 200px
}
}
#media (max-width: 460px) {
.test {
background: #ff0;
height: 100px
}
}
<div class="test"></div>
Firefox, using Dev Console ruler to show window size:
Display Scale: 100% (i.e. no scaling) at 1119px width - CSS works as expected*
#media (min-width: 720px) and (max-width: 1119px) {
.test { margin-left: 300px; background: #0FF; height: 200px }
}
Display Scale 125% at 1119px width - no CSS media query applied, so CSS reverts to original
.test { border: 10px solid #f00; height: 10px; }
Possible Reason for the "glitch"
If the above is the case (or even if it isn't), I suspect your next question is why is it happening. Only the developers can answer that, but thinking logically we can come up with the reasoning below.
What are media queries meant to do?
First, we need to look at the purpose of media queries. According to the W3C CSS3 Media Queries recommendation:
The ‘width’ media feature describes the width of the targeted display area of the output device.
From this, we can assume they were intended for selecting the CSS to use depending on the media query that matches the screen/window size. Screen size can't have fractional pixels (e.g. 719.5px) and points between the whole pixels can only "exist" while the screen is being resized, and media queries are not intended to cover such temporary transitions.
OK, that's the why it isn't necessarily a "bug" and why it isn't always handled well in browsers, now...
What is causing this issue to happen during transitions?
If you have changed the scale, the browser has to recalculate the all the sizes to scale them up/down also. This "glitch" in the transition is most likely being caused by these calculations resulting in fractions of pixels. (If you haven't changed the scale, the same logic actually still applies)
It appears the browsers such as Chrome have been build to handle the recalculations/ size change in whole pixels, so the display will jump from the CSS applied by (e.g.) max-width:719px media query to the CSS for min-width:720px.
However other browsers such as Firefox don't seem to work like this and try to calculate the display based on the fractional pixels. This means there can be instances where the recalculated/changing size fall between e.g. max-width:719px nor min-width:720px.
In this case it seems to change the display to whatever CSS applies at that point - if there is another media query overlapping those sizes that would be applied, but more likely the original CSS is getting applied. So what you are seeing in that transition you describe is your CSS that exists outside of the media queries, e.g. if your CSS is written for mobile-first then you are seeing the CSS for mobile version of the site.
What can we do to "fix" it?
Aside from changing back the scale to 100% (which isn't a feasible option because you can't ask all your visitors to do that!) I don't know if there is a reliable solution.
One option is to use decimal values in your media queries like you mentioned, e.g.
#media (min-width: 720px) and (max-width: 1119.999px) { /* CSS....*/ }
#media (max-width: 719.999px) { /* CSS....*/ }
Another is to try is to make sure that you have suitable styling in your original CSS that will be applied at the "in-between" points, e.g. 719px - 720px.
Firefox and Edge appear to calculate and store their view port widths as floating point numbers, and media queries are applied to those values rather than the whole-pixel widths that they represent. There is consequently a difference in the way in which the parameters of our media queries are interpreted.
So whilst Chrome and Opera transition between 720 pixels and 719 pixels seamlessly, the same transition on Firefox or Edge can result in the browsers' simply skipping over the query and applying whatever default styling is otherwise relevant.
My original solution was to apply a browser-specific #media query to account for values between the whole pixels.
#-moz-document url-prefix() /* Firefox */
{
#media only screen and (min-width: 719.000001px) and (max-width: 719.999999px)
{
However, the real problem was the way in which I was specifying the parameters of the media queries. Unlike in programming languages, in which we can (and should) define mathematical parameters with equality and inequality (e.g. -1 ≤ x ≤ 1), CSS employs a hierarchy. For example, if #media (max-width: 600px) is followed by #media (max-width: 400px), whilst the two are not logically exclusive, the latter query will take precedence over the former.
So my solution was to change the way in which the #media queries were structured, such that there were max-width declarations only. If we try to define upper and lower limits of each interval, we run into the aforementioned problems with the way that the distinct browsers interpret the limits.
You could avoid any requirement to set up specific decimals by having no gaps between your queries at all.
For example:
(min-width 1px) // Instead of (max-width: 719px)
(min-width 720px) // Instead of (min-width: 720px) and (max-width: 1119px)
(min-width 1120px ) // Instead of (min-width: 1120px)
Currently, you have a middle band with one 'max-width' band and one 'min-width' band either side of it.
The above alternative solution just uses 1 direction (min-width), so there are no gaps to contend with.
Or:
That solution assumes you don't want to develop your whole front-end style for sub-720px and then media-query every larger size.
If you did want to do that, you could always just use the following: (sure Google search SEO may love you, but you may hate it!)
(min-width 720px) // Instead of (min-width: 720px) and (max-width: 1119px)
(min-width 1120px ) // Instead of (min-width: 1120px)
You would then need to incorporate your code that you wanted to put in your max-width: 719px media query into your base ("non- media query") code.
Which one?
I'd use the first solution.
Based on the OP, that one would be more applicable in that situation too.
Actually, I wouldn't use the first solution. I'd code for, say, >1230px, and then use media queries that use max-width for the responsive steps below that.

Resizing div based on device

So I'm having trouble getting my div to resize based on if it's a mobile (specifically smartphone) device. Now the mobile device I'm using is the iPhone7plus. So I'm not sure if the dimensions I have are for this device.
my original css (for desktop) is this:
div#allContent div#mainContent div#contentText {
width:50%;
/*other styles*/
}
So the text on the screen is on one half of the page and the signup form will be on the other half. Now when I view in my iPhone the drop down items from the form are too big and I can't see the text inside the drop down boxes. So I'm trying to get the width of the contentText div to be 100% then also the form div to be 100%.
I added this to the bottom of my css file
I've tried this first line to:
/*#media only screen and (min-device-width:320px) and (max-device-width:480px) {
#media screen and (min-device-width:320px) and (max-device-width:480px) {
div#allContent div#mainContent div#contentText {
width:100%;
}
div#allContent div#mainContent div#signupContent {
width:100%;
}
}
Is it because I have a larger mobile device that it's not working? Should i increase the max values? I'm just learning mobile device support.
Mobile device max-width can be 767 after that i pad and notepad device width starts.
#media screen and (min-device-width:320px) and (max-device-width:767px) {
//code comes here
}
I think the media query syntax is different in your code
#media screen and (max-width: 480px){
}
I hope this media query will work for iphone portrait mode.
Maybe your problem is a syntax or you are not selecting the target correctly, if you post your full code (HTML and CSS) we could be more helpful.
Regardless, you could use min-width and max-width instead of *-device-width.
I have created example on CodePen, check it out it will help you.

Target ONLY smartphones with media query

I have a video background and since it takes quite a lot of MB to load that, I want to disable the video on smartphones.
The CSS itself is easy:
video{
display:none;
}
But, how to get the media query so that it won't affect desktop and laptop screens? Because smartphones are getting higher and higher resolutions and the old method of just targeting a smaller amount of pixels (±450px e.g.) won't work with newer smartphones anymore.
The width and height of the smartphone shouldn't matter, I fixed that in my 'regular' media queries, so that the css changes when my design breaks.
Use something like
#media (max-width: 480px) {
video {
display: none;
}
}
This will display nothing for screen sizes with a maximum of 480 pixels (majority of smartphones)

What is the best way to detect smaller devices like mobiles or tablets in CSS?

When i read about responsive design, people always seam to use this statement:
#media screen and(max-width: )
But mobile phones today seem to have really great resolution (often more than pc), whats the best way to detect small devices?
Thx ;=)
The screen resolution does not matter. The value used in media queries is the device width. For example:
My phone has a screen with a resolution of 1280x720 pixels. When held upright (in portrait mode) the width is 720px, but since it is an HD screen, it has a 200% ratio, and the resulting device width is 360px. This is the value used in media queries:
/* Even though my phone has a screen width of 720px… */
#media screen and (max-width: 360px) {
/*
* This code will apply
*/
}
#media screen and (min-width: 361px) {
/*
* This code will not apply
*/
}
The general rule is that phones in portrait mode have a device width less or equal to 400px, regardless of how many actual pixels their screen contains.
You can't directly query physical size.
You can, however, perform a media-type query for DPI along with Height and Width.
Example
#media(resolution: 326dpi) and (device-width: 640) and (device-height: 1136) {
// Iphone 5s
}
This should be a good starting point: List of displays by pixel density
Physical pixels and CSS pixels are not the the same on retina/HD mobile displays.
Research the viewport meta tag for information on device-width. i.e. <meta name="viewport" content="width=device-width"> is the CSS pixel width scaled at 100%.
See Viewport Device-Widths for a list of common mobile screen sizes.
When you are doing responsive design, you don't actually "detect" the screen size, rather you "target" various size using CSS Media Queries.
If you are using a library like Modernizer for example, that's when you are actually doing detection for various properties.

Media Queries for Phones

I'm using media queries in my css:
/* Tablet */
#media (max-width: 979px){
}
/* Phone */
#media (max-width: 767px){
}
When I drag my browser really small on my desktop computer it switches to the phone layout, is there a way to prevent this so the small size is only seen on the phone?
There isn't really a need to do this. This is the point of responsive, it's device-agnostic. So if a user comes to your site on desktop but their browser is really skinny the content will fit it (such as the Windows 8 Metro IE10 sidebar thing). You don't want to limit it only to phones, once you've done that you're going down a road that isn't meant to be traveled with responsive.
Sure you can, but the question is you really think the overkill need for it will be valid?
You can add a class to the HTML tag for phone devices (using JavaScript or any other method to verify if its a phone or not) and use this class inside the #media so only when this class is applied the media queries will take effect, small example:
HTML:
<html class="phone-device">
</html>
CSS:
/* Phone */
#media (max-width: 767px){
.phone-device{
}
}
But again this is not the right thing to do...