During the development of several interactive web pages, I have learnt a lot. Here are some interesting findings.
Scroll Bar's Height
Sometimes when we have:
#title {
position: absolute;
left: 0;
bottom: 0;
}
to prevent the browser' scroll bar from covering our web page's content;
we need to subtract the page' size by the scroll bar's width;
const scrollBarWidth = () => {
let inner = document.createElement('p');
inner.style.width = "100%";
inner.style.height = "200px";
let outer = document.createElement('div');
outer.style.position = "absolute";
outer.style.top = "0px";
outer.style.left = "0px";
outer.style.visibility = "hidden";
outer.style.width = "200px";
outer.style.height = "150px";
outer.style.overflow = "hidden";
outer.appendChild(inner);
document.body.appendChild(outer);
let w1 = inner.offsetWidth;
outer.style.overflow = 'scroll';
let w2 = inner.offsetWidth;
if (w1 == w2) w2 = outer.clientWidth;
document.body.removeChild(outer);
return (w1 - w2);
};
So, it will looks like:
Credit to http://www.alexandre-gomes.com/?p=115.
Dynamic Viewport Height
To fit elements to the height of the viewport, we often think to set the height to 100vh
. Unfortunately, this will contribute to a headache when we target mobile devices, because we often see the address bar disappear when scrolling. Until all major browsers support dv*
units, we can create our own scale units. In CSS:
#main-container {
height: calc(var(--dvh, 1vh) * 100);
}
In JavaScript:
let dvh = window.innerHeight * 0.01;
document.documentElement.style.setProperty("--dvh", dvh + "px");
This technique will become more of use when dealing with elements with a defined aspect ratio. Consider we have this on iPad:
We can set, for example, the font size as:
.title {
font-size: calc(var(--dvh, 1vh) * 15);
}
But on iPhone, we have this instead:
The font size will not scale as expected. To get rid of this situation, we can do as follow. In CSS:
.title {
font-size: calc(var(--dch, 1vh) * 15);
}
In JavaScript:
// Resize the container to fit the screen
let mainContainer = document.getElementById("main-container");
...
// Create a custom unit
let dch = mainContainer.style.height * 0.01;
document.documentElement.style.setProperty("--dch", dch + "px");
So, it will looks like:
Credit to https://css-tricks.com/the-trick-to-viewport-units-on-mobile/.
Specific Browser Identification
As good web developers, we must ensure that our web pages look equally correct—not necessarily to be precisely the same—on every target browser running on different operating systems. Sadly, we got this:
with CSS as below:
#start-button {
padding: calc(var(--canvasHeight, 1vh) * 0.75) 0;
padding-bottom: calc(var(--canvasHeight, 1vh) * 1.0);
font-size: calc(var(--canvasHeight, 1vh) * 8);
...
}
Let us take a closer look. In Chrome:
In Firefox:
See? I guess, this is related with this "bug".
Someone may have found a better solution, but I would think that I need to apply separate styles with duck-typing technique for Chrome and the others.
For example, we could add:
/*
* Chrome-only CSS hacks
**/
@supports (not (-webkit-hyphens: none)) and (not (-moz-appearance: none)) and (list-style-type:"*") {
#start-button {
padding-bottom: calc(var(--canvasHeight, 1vh) * 2.0);
}
}
So that it can looks as:
Let us zoom in a little:
Perfect!
Credit to https://browserstrangeness.github.io/css_hacks.html. Please go to the page to find out more.
In rare cases, we may also want to make our web pages work in other browsers such as Samsung Internet and UC Browser, as they both have accordingly 3% and 1.5% market share in our country. But the previous reference does not include those browsers. In this case, we could have to put this in CSS:
/*
* UC Browser-only CSS hacks
**/
html[data-useragent*='UCBrowser'] #start-button {
padding-bottom: calc(var(--canvasHeight, 1vh) * 2.0);
}
In JavaScript:
var root = document.documentElement;
root.setAttribute('data-useragent', navigator.userAgent);
root.setAttribute('data-platform', navigator.platform );
Credit to https://stackoverflow.com/a/29938371/8791891.
Not only the way each browser renders the page, but also how they implement things. I had several Safari-specific issues like the ended
media event not firing and there is audio playback delay. It made me thinking to identify the browser with another duck-typing technique, similar to:
const isSafari = () => {
return /constructor/i.test(window.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window['safari'] || (typeof safari !== 'undefined' && window['safari'].pushNotification));
}
Credit to https://stackoverflow.com/a/9851769/8791891.
Specific Device Identification
In other chances, we may want to make a different implementation based on the user's device type. Let us say that we do not want to enable anti-aliasing to the HTML5 canvas on mobile devices. We can have this code:
const isMobileDevice = () => {
const agent = navigator.userAgent || navigator.vendor || window.opera;
return (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(agent)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(agent.substr(0,4)));
};
Credit to https://stackoverflow.com/a/11381730/8791891
Sometimes, we might find that our web pages do not look the same on desktop and on mobile. Even though they are both Firefox. At this point, we may want to differentiate between the two based on the available media features, combined with the browser detection hack;
/*
* Firefox on touch input device-only CSS hacks
**/
@supports selector(:-moz-is-html) {
@media (any-pointer: coarse) and (not (any-pointer: fine)) {
#start-button {
padding-bottom: calc(var(--canvasHeight, 1vh) * 2.0);
}
}
}
Although, well, this is not accurate.
Credit to https://css-tricks.com/interaction-media-features-and-their-potential-for-incorrect-assumptions/.
See you later!
Top comments (0)