A more reliable method for detecting horizontal and vertical screens on mobile devices

A more reliable method for detecting horizontal and vertical screens on mobile devices

[[171604]]

Not long ago, I did an H5 project and needed to do some processing when the horizontal and vertical screens changed. Of course, I needed to use orientationchange to monitor the changes of the horizontal and vertical screens.

Solution 1:

  1. // Listen for orientation changes
  2. window.addEventListener( "orientationchange" , function (event) {
  3. // Determine the horizontal or vertical screen orientation based on event.orientation|screen.orientation.angle being 0|180, 90|-90 degrees
  4. }, false );

After the code is added, various compatibility issues arise. The compatibility issues arise in two places:

  • orientationchange
  • event.orientation|screen.orientation.angle

The compatibility of orientationchange event is as follows:

The following are the compatibility of screen.orientation:

Option 2:

The above solution doesn't work, so I have to find another way. After searching on Google, I found that it can be achieved by resizing (window.inner/outerWidth, window.inner/outerHeight):

  1. window.addEventListener( "resize" , function (event) {
  2. var orientation=(window.innerWidth > window.innerHeight)? "landscape" : "portrait" ;
  3. if(oritentation === 'portrait' ){
  4. // do something…
  5. } else {
  6. // do something else
  7. }
  8. }, false );

This solution basically meets the needs of most projects, but it still has some shortcomings:

  • As long as the size of the window changes, the resize event will be triggered continuously. You can use setTimeout to optimize it.
  • If multiple places need to monitor the horizontal and vertical screen changes, multiple window.addEventListener("resize", function(event) {……}) need to be registered. Can it be improved through the subscription and publishing mode, and only one resize is registered to monitor the horizontal and vertical screen changes, and the notification subscription object is published as long as the horizontal and vertical changes. Other places that need to monitor the horizontal and vertical screens only need to subscribe.

The key codes are as follows:

  1. var resizeCB = function (){
  2. if(win.innerWidth > win.innerHeight){//initialization judgment
  3. meta.init = 'landscape' ;
  4. meta.current = 'landscape' ;
  5. } else {
  6. meta.init = 'portrait' ;
  7. meta.current = 'portrait' ;
  8. }
  9. return   function (){
  10. if(win.innerWidth > win.innerHeight){
  11. if(meta. current !== 'landscape' ){
  12. meta.current = 'landscape' ;
  13. event.trigger ( '__orientationChange__' , meta);
  14. }
  15. } else {
  16. if(meta. current !== 'portrait' ){
  17. meta.current = 'portrait' ;
  18. event.trigger ( '__orientationChange__' , meta);
  19. }
  20. }
  21. }
  22. }();

Click here for the complete code

Option 3:

However, I think that the detection by window.innerWidth > window.innerHeight is a pseudo detection, which is a bit unreliable. Can the detection be implemented through the browser? For example, based on CSS3@media media query.

@media compatibility is as follows:

As shown in the figure above, mobile browsers all support CSS3 media.

Implementation ideas:

  • Create a specific CSS style that contains the horizontal and vertical screen states
  • Inject CSS code into the page via JS
  • Get the horizontal and vertical screen status in the resize callback function

Here I choose the font-family of the <html></html> node as the detection style attribute. The reasons are as follows:

  • Choose <html></html> mainly to avoid reflow and repaint
  • The font-family style is chosen mainly because font-family has the following characteristics:

1. Give priority to the fonts that are listed first.

2. If the font cannot be found or does not include the text to be rendered, the next font is used.

3. If none of the listed fonts meet your needs, let the operating system decide which font to use.

In this way, we can specify a specific logo to indicate the horizontal and vertical screen status, but the specified logo needs to be placed in front of other fonts so that it will not cause changes in the hmtl font.

The key codes are as follows:

  1. // callback
  2. var resizeCB = function () {
  3. var hstyle = win.getComputedStyle(html, null ),
  4. ffstr = hstyle[ 'font-family' ],
  5. pstr = "portrait, " + ffstr,
  6. lstr = "landscape, " + ffstr,
  7. // Splicing css
  8. cssstr = '@media (orientation: portrait) { .orientation{font-family:' + pstr + ';} } @media (orientation: landscape) { .orientation{font-family:' + lstr + ';}}' ;
  9. // Load the style
  10. loadStyleString(cssstr);
  11. // Add class
  12. html.className = 'orientation' + html.className;
  13. if (hstyle[ 'font-family' ] === pstr) { // Initialization judgment
  14. meta.init = 'portrait' ;
  15. meta.current = 'portrait' ;
  16. } else {
  17. meta.init = 'landscape' ;
  18. meta.current = 'landscape' ;
  19. }
  20. return   function () {
  21. if (hstyle[ 'font-family' ] === pstr) {
  22. if (meta. current !== 'portrait' ) {
  23. meta.current = 'portrait' ;
  24. event.trigger ( '__orientationChange__' , meta);
  25. }
  26. } else {
  27. if (meta. current !== 'landscape' ) {
  28. meta.current = 'landscape' ;
  29. event.trigger ( '__orientationChange__' , meta);
  30. }
  31. }
  32. }
  33. }();

Click here for the complete code

Test results

  • Portrait effect:

  • Landscape effect:

Option 4:

It can be improved further. When orientationchange is supported, use the native orientationchange. If it is not supported, use solution three.

The key codes are as follows:

  1. // Whether to support orientationchange event
  2. var isOrientation = ( 'orientation'   in window && 'onorientationchange'   in window);
  3. // callback
  4. var orientationCB = function (e) {
  5. if (win.orientation === 180 || win.orientation === 0) {
  6. meta.init = 'portrait' ;
  7. meta.current = 'portrait' ;
  8. }
  9. if (win.orientation === 90 || win.orientation === -90) {
  10. meta.init = 'landscape' ;
  11. meta.current = 'landscape' ;
  12. }
  13. return   function () {
  14. if (win.orientation === 180 || win.orientation === 0) {
  15. meta.current = 'portrait' ;
  16. }
  17. if (win.orientation === 90 || win.orientation === -90) {
  18. meta.current = 'landscape' ;
  19. }
  20. event.trigger (eventType, meta);
  21. }
  22. };
  23. var callback = isOrientation ? orientationCB() : ( function () {
  24. resizeCB();
  25. return   function () {
  26. timer && win.clearTimeout(timer);
  27. timer = win.setTimeout(resizeCB, 300);
  28. }
  29. })();
  30. // Listen
  31. win.addEventListener(isOrientation? eventType: 'resize' , callback, false );

Click here for the complete code

Option 5:

At present, the above solutions are all implemented through customized subscription and publishing event modes. Here, we can simulate orientationchange based on the browser's event mechanism, that is, fix the incompatibility of orientationchange.

The key codes are as follows:

  1. var eventType = 'orientationchange' ;
  2. // Trigger native orientationchange
  3. var fire = function () {
  4. var e;
  5. if (document.createEvent) {
  6. e = document.createEvent( 'HTMLEvents' );
  7. e.initEvent(eventType, true , false );
  8. win.dispatchEvent(e);
  9. } else {
  10. e = document.createEventObject();
  11. e.eventType = eventType;
  12. if (win[eventType]) {
  13. win[eventType]();
  14. } else if (win[ 'on' + eventType]) {
  15. win[ 'on' + eventType]();
  16. } else {
  17. win.fireEvent(eventType, e);
  18. }
  19. }
  20. }

Click here for the complete code

Through the above five solutions, I have a deeper understanding of mobile terminal horizontal and vertical screen detection. Some things can only be understood by yourself when you have experienced them. I also recorded the reasons in the article, hoping to help everyone. After the evolution of five solutions, the final orientationchange-fix was obtained, github address: https://github.com/zhansingsong/orientationchange-fix

<<:  What are Alibaba and JD.com’s VR+ shopping waiting for?

>>:  iOS development history: from iPhone OS 1.0 to iOS10, finally supports harassment blocking

Recommend

There is a medicine called "Ten Merits"

A few days ago, the People's Daily published ...

Marketing and promotion skills of corporate Weibo

In the turbulent Web 2.0 era, an important means ...

The most expensive container in the world is in you and me.

If a basin of water is not placed properly, the w...

How can online education improve purchase conversion rate?

If you are working in the education industry, you...

Do you know how to solve the 3 most important equations in APP operation?

During APP operation , there are a large number o...

Unlocking hydrogen innovation: towards a sustainable future

Hydrogen energy innovation will set off a green r...

Potatoes, an overlooked staple food

When it comes to potatoes, what is your first rea...