最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Differentiating between portrait mode on handheld devices and desktops - Stack Overflow

programmeradmin5浏览0评论

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:

  1. all devices bellow/between set widths
  2. only devices (using a JavaScript shim to fix media queries) bellow/between set widths and orientation.

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 es 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 bees > 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 es 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.

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:

  1. all devices bellow/between set widths
  2. only devices (using a JavaScript shim to fix media queries) bellow/between set widths and orientation.

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 es 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 bees > 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 es 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.

Share Improve this question edited Jan 10, 2013 at 7:28 Patrick asked Nov 17, 2012 at 12:39 PatrickPatrick 3,4981 gold badge38 silver badges64 bronze badges 1
  • Just a forethought. But all modern handhelds have html5 standard. So if the device doesn't support a css3 prop, then it's probably a desktop – SpYk3HH Commented Dec 12, 2012 at 1:46
Add a ment  | 

5 Answers 5

Reset to default 5 +50

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.

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

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 paring 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.

For pleteness, 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 ments, 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

A great javascript library is css3-mediaqueries-js.

发布评论

评论列表(0)

  1. 暂无评论