CSS Media Query - Soft-keyboard breaks css orientation rules - alternative solution?
I know this is a couple of years late but I found a great solution
For landscape media:
@media screen and (min-aspect-ratio: 13/9) { /* landscape styles here */}
And for portrait media:
@media screen and (max-aspect-ratio: 13/9) { /* portrait styles here */}
The full solution and why it works can be found here Michael Barret - Android browser challenges
Edit: this link is now expired, but a snapshot can be found on the internet archive: Michael Barret - Android browser challenges
The problem lies in the way that orientation is calculated:
http://www.w3.org/TR/css3-mediaqueries/#orientation
The ‘orientation’ media feature is ‘portrait’ when the value of the ‘height’ media feature is greater than or equal to the value of the ‘width’ media feature. Otherwise ‘orientation’ is ‘landscape’.
Since the height/width is calculated on the visible viewport, the soft keyboard apparently causes the orientation to flip now that the viewport width is less than the height. One solution would be just to use your media queries based on just width
instead. This makes it more flexible across devices regardless of orientation, not to mention width/height is more widely supported than orientation.
If you want to account for the width instead of orientation, I'll use the iPhone as an example:
@media screen and (max-width: 320px) {
/* rules applying to portrait */
}
@media screen and (max-width: 480px) {
/* rules applying to landscape */
}
This approach is more flexible than orientation since the queries aren't limited to devices/user-agents that support orientation, not to mention that orientation tells you very little versus the width.
Of course if you really need to know orientation, it seems like setting the class initially and just use that might be your best option.
An alternative might be to use device-aspect-ratio
, which remains unchanged. However, in Webkit, rotating the device doesn't trigger an update of CSS rules using this query, even though JavaScript tests return true for the new aspect ratio. This is apparently due to a bug, but I'm not able to find a bug report. Using a combination of orientation
and {min,max}-device-aspect-ratio
seems to work fine:
@media screen and (max-device-aspect-ratio: 1/1) and (orientation: portrait)
@media screen and (min-device-aspect-ratio: 1/1) and (orientation: landscape)
The use of orientation
triggers updates as expected, and the use of device-aspect-ratio
restricts updated to actual changes of orientation.
I worked through the options listed above and none quite fixed the issues for me. I switched to using screen.availHeight as it gives consistent height results avoiding the keyboard display issue.
// Avoiding the keyboard in Android causing the portrait orientation to change to landscape.
// Not an issue in IOS. Can use window.orientation.
var currentOrientation = function() {
// Use screen.availHeight as screen height doesn't change when keyboard displays.
if(screen.availHeight > screen.availWidth){
$("html").addClass('portrait').removeClass('landscape');
} else {
$("html").addClass('landscape').removeClass('portrait');
}
}
// Set orientation on initiliasation
currentOrientation();
// Reset orientation each time window is resized. Keyboard opening, or change in orientation triggers this.
$(window).on("resize", currentOrientation);
For me, this did the trick:
@media screen and (max-device-aspect-ratio: 1/1), (max-aspect-ratio: 1/1){
/*Portrait Mode*/
};
While max-aspect-ratio
takes care of triggering Portrait mode simply by resizing the window (useful for PCs and other landscape-only devices), max-device-aspect-ratio
helps with smartphones or other devices with variable orientation. And because I'm not declaring specific settings for Landscape mode, even if max-aspect-ratio
is reporting >1 to the system, Portrait mode will still be triggered by max-device-aspect-ratio
if the Android device is oriented that way.
The 1/1
part basically means that if the ratio is <=1, it goes to Portrait mode, otherwise it goes to landscape mode.