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

Xiaohongshu product analysis report!

Xiaohongshu has accumulated a user word-of-mouth ...

Dingxiang Mama_Medical Cosmetic Surgery Guide 2021 Edition

Dingxiang Mama·Medical Cosmetic Surgery Guide 202...

How to operate CPD delivery? There are these processes!

We have learned about the delivery of CPD before,...

How to apply for a 400 phone number?

400 telephone is a service that shares the cost b...

Android Training - Managing your app's memory

Random Access Memory (RAM) is a valuable resource...

Three-cycle trading system stock application course

Course Catalog Section 1 Three-cycle stock select...

Red Business School - Fearless Little Red Book Operation Course 5.0

Chapter 1 The official website has not been updat...

Another sighting? Is it the truth or the Loch Ness Monster?

In June 2023, French tourists Etienne and Eliane ...

No. 1 in hot search, Zhong Xuegao responded!

Yesterday at noon, @钟薛高 issued a statement, Ranke...

Live broadcast account operation course

Introduction to live broadcast account operation ...

How to create a creative H5? Learn about the real H5 in one article

In recent years, H5 has been very popular, and th...