Reputation: 3498
I'm looking for a reliable media query rule that is:
If desktop width < 720px AND devices in portrait mode {}
(that is, as the width decreases on desktop, the media query kicks in at 720px. On phones, this should only happen when it is in portrait mode - landscape should not have the media query applied)
The problem is: how to target devices separately from desktops.
Problem exists because: @media handheld
is not supported
Additionally max-width
effects everything, so it can't be used in conjunction with max-device-width AND portrait
Seems like I can only target either:
CANNOT treat devices and desktops separately.
Is there an existing JavaScript solution which would fulfill my needs?
note I am coding my CSS in LESS, the media queries are nested within.
Background
The site I am working on is responsive and uses a grid system. At 720px width (current testing width) column usage changes for smaller devices / resolutions. Upon testing, however, the site (full site at 720px width) was pleasantly readable in landscape, even on my small screen HTC Desire. As I am removing portions of the site for better usability with media queries, I thought why not have the site normally accessible in landscape.
Bellow 720px on a desktop without modifying element column spans sees a pretty crushed site. However, due to the smaller nature of a mobile device it doesn't appear so. However with the column span modifications, particular elements are simply out of proportion (such as the heading) when it comes to landscape on a phone (due to the much reduced height of the browser).
Simply put, changing the design purely on browser width doesn't carry across all devices equally, as I have managed to achieve on other sites.
I am using the following meta tag:
<meta name="viewport" content="width=device-width,
initial-scale=1,
maximum-scale=1,
user-scalable=no" />
What's been tried
Orientation is irrelevant on desktops. It changes depending on user window settings, resolution, etc etc.
I have tried the following to target phones/both:
@media handheld and (orientation:portrait) { }
No phones it seems take advantage of the handheld
attribute, at least, 100% do not - so it's worthless.
@media screen and (max-device-width:720px) and (orientation:portrait) { }
Would work great, but android 2.2 and 2.3 (possibly others, not to mention other OS?) have issues with max-device-width
not working.
@media screen and (max-width:720px) and (orientation:portrait) { }
Works on high res monitors (since height quickly becomes > width as you decrease width of the window) and phones, but wont work on smaller monitors, as the windows wont be portrait at 720px width (site keeps condensing past the limits I want).
@media screen and (max-width:720px), screen and (orientation:portrait) { }
Will do whatever comes first. No use.
@media screen and (max-width:720px), screen and (max-width:500px) and (orientation:portrait) { }
and
@media screen and (max-width:720px) { }
@media screen and (max-width:500px) and (orientation:portrait) { }
Everything simply uses the larger max-width
.
I've also had a fiddle with min/max-height
with no success either.
Upvotes: 16
Views: 1559
Reputation: 3498
For completeness, this is to explain how to use CSS selectors to qualify the use of media queries in the context of nested LESS.
@enginefree's answer, and the following comments, explained how to check for a mobile device, it's orientation and to manipulate an elements attributes based upon the result.
The following code illustrates how to use the LESS &
and CSS3 :not
selectors to display our media queries when the attribute or class we are looking for is not detected:
body {
/* this has the possible class or data attribute of 'mobile' */
/* this is not included in the nest as you can't climb at will */
/* the class or attribute (via our JavaScript) could be applied
to any element that sits above and outside of `#level-1` in
this example */
}
#level-1 {
#level-2 {
#level-3 {
#level-4 {
body:not(.mobile) & {
/* produces the following CSS */
/* body:not(.mobile) #level-1 #level-2 #level-3 #level-4 { } */
/* rules in this block will only be executed if body does not have a mobile class */
@media screen and (max-width:) {
}
}
body:not([data-device=mobile]) & {
/* produces the following CSS */
/* body:not([data-device="mobile"]) #level-1 #level-2 #level-3 #level-4 { } */
/* rules in this block will only be executed if body does not have a mobile data-device attribute */
@media screen and (max-width:) {
}
}
}
}
}
}
If the body
element was part of this nest, you would end up with the following CSS, and this should explain why the element must exist out of the scope of the nest, as well as above it:
body:not(.mobile) body #level-1 #level-2 #level-3 #level-4 { }
Read more about the &
operator
Upvotes: 1
Reputation:
I think the best method is, according to MDN (Mozilla Developer Network) using window.innerHeight
documentation here and window.innerWidth
documentation here where it measures the browsers width and height in pixals to determine the orientation.
//Detect mobile platform
var isMobile = {
Android: function() {
return navigator.userAgent.match(/Android/i);
},
BlackBerry: function() {
return navigator.userAgent.match(/BlackBerry/i);
},
iOS: function() {
return navigator.userAgent.match(/iPhone|iPad|iPod/i);
},
Opera: function() {
return navigator.userAgent.match(/Opera Mini/i);
},
Windows: function() {
return navigator.userAgent.match(/IEMobile/i);
},
any: function() {
return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows());
}
};
if ( isMobile.any() ) {
if (window.innerHeight > window.innerWidth) {
console.log("Orientation is in portrait");
}
else {
console.log("Orientation is in landscape");
}
}
else {
console.log("Mobile platform not detected.");
};
More documentation here for mobile platforms.
Upvotes: 5
Reputation: 6203
You should look into Modernizr. It includes feature detection/inference for virtually all useful modern browser features, notably including whether the device is touch-based via a simple Boolean check on Modernizr.touch
. From there, you may be able to get away with testing for portrait/landscape by comparing document.width to document.height, something like:
if(Modernizr.touch) {
// is touch device
if(document.height > document.width) {
// is in portrait
} else {
// is in landscape
}
} else {
// not touch device
}
Note that, as you've discovered, there is no perfect test for touch/desktop, so if you incorporate the Modernizr touch test (or roll your own), it would be good to consult this page that explains which touch tests are reliable, when.
Upvotes: 1
Reputation: 2902
Well these three rules cover most mobile devices
@media only screen and (min-width: 768px) and (max-width: 959px) @media only screen and (min-width: 480px) and (max-width: 767px) @media only screen and (max-width: 479px)
Alternatively try using the Skeleton Responsive framework
Upvotes: 1