Responsive font size using CSS/jQuery - javascript

I want to create a responsive text inside a div.
I tried jquery-textfill and FlowType, but they are not working for me at all.
FlowType does not use all the available space, only a part of it (demo), while textfill does not respect the height (demo).
Am I using them incorrecly or what I want is too hard to achieve?
My HTML:
<body>
<div class="external">
<div class="internal">Example</div>
</div>
</body>
My CSS:
.internal{width:100%;height:100%}
.external{width:400px;height:50px;}
PS. Viewports are not supported enough for now.

EDIT: Updated with resize event listener. Updated fiddle.
As I understand it, you want the text to be as large as possible while still fitting inside the containing <div>, correct? My solution is to put a <span> around the text, which conforms to the text's normal size. Then calculate the ratios between the container's dimensions and the <span>'s dimensions. Whichever is the smaller ratio (either width or height), use that ratio to enlarge the text.
HTML:
<div class="container">
<span class="text-fitter">
text here
</span>
</div>
JS (jQuery):
textfit();
$(window).on('resize', textfit);
function textfit() {
$('.text-fitter').css('font-size', 'medium');
var w1 = $('.container').width()-10;
var w2 = $('.text-fitter').width();
var wRatio = Math.round(w1 / w2 * 10) / 10;
var h1 = $('.container').height()-10;
var h2 = $('.text-fitter').height();
var hRatio = Math.round(h1 / h2 * 10) / 10;
var constraint = Math.min(wRatio, hRatio);
$('.text-fitter').css('font-size', constraint + 'em');
}
Here's a fiddle. Adjust the .container dimensions in the CSS to see it in action.

CSS
.internal{width:100%;height:100%}
.external{width:auto;height:auto;background-color:yellow}
JQuery
$(".external").fitText(0.5);
DEMO 1
Update 1:
CSS
.internal{width:auto;height:auto;position:absolute;}
.external{width:400px;height:50px;background-color:yellow;position:relative;}
JQuery
$(".external").fitText();
DEMO 2
Update 2:
JQuery
var ex=$(".external");
var h=ex.height();
var w=ex.width();
ex.fitText(Math.min(h,w)/Math.max(h,w) );
DEMO 3
Update 4:
Bigtext is a jQuery text plugin that automatically enlarge the font size of your text to fill its parent container, without overflowing the container Div.
jQuery Bigtext Plugin

For anyone who stumbles upon this old post, I have found a solution I consider perfect.
You take this beautiful plugin written by Dave Rupert, configure the settings to your liking, and I added a wrapper for it that allows you to define the elements you want to resize. It also stores the original font size so when you scale back up, the text is limited by it's original size, otherwise it scales without limit.
Here's a snippet and a jsfiddle. JSFiddle
NOTE: the snippet only runs on resize in JSFiddle so be sure to resize your screen. In production it runs on load.
var headings = [$('h1'), $('h2'), $('h3')]
$.each(headings, function(index, heading) {
var fontsize = heading.css('font-size');
$(window).on('load resize', function() {
if (heading.parent()[0] &&
heading.parent()[0].scrollWidth > $('.container').innerWidth()) {
heading.fitText(1, {
minFontSize: '10px',
maxFontSize: fontsize
});
}
});
});
/*global jQuery */
/*!
* FitText.js 1.2
*
* Copyright 2011, Dave Rupert http://daverupert.com
* Released under the WTFPL license
* http://sam.zoy.org/wtfpl/
*
* Date: Thu May 05 14:23:00 2011 -0600
*/
$.fn.fitText = function(kompressor, options) {
// Setup options
var compressor = kompressor || 1,
settings = $.extend({
'minFontSize': Number.NEGATIVE_INFINITY,
'maxFontSize': Number.POSITIVE_INFINITY
}, options);
return this.each(function() {
// Store the object
var $this = $(this);
// Resizer() resizes items based on the object width divided by the compressor * 10
var resizer = function() {
$this.css('font-size', Math.max(Math.min($this.width() / (compressor * 10), parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize)));
};
// Call once to set.
resizer();
// Call on resize. Opera debounces their resize by default.
$(window).on('resize.fittext orientationchange.fittext', resizer);
});
};
.container {
width: 80vw;
background: yellow;
}
h1 {
font-size: 5rem;
}
h2 {
font-size: 4rem;
}
h3 {
font-size: 3rem;
}
h4 {
font-size: 1rem;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<h1>GIGANTICFONT</h1>
</div>
<div class="container">
<h2>LargishFont</h2>
</div>
<div class="container">
<h3>Mediumfont</h3>
</div>
<div class="container">
<h4>smallfont</h4>
</div>

Related

How can I 'page zoom' on mobile browser

There are two types of zoom. The 'pinch zoom' you get on mobile browsers where content disappears off the edges of the screen. And the 'page zoom' you get on desktop browsers, like when you do Ctrl +. After 'page zoom' the page is re-flowed, so with, a responsive layout you still see the whole page width.
How can I allow users to 'page zoom' on mobile devices?
I am thinking there could be a Zoom + and Zoom - button on the header bar of my site. I want this because I have a web app that the majority of users like, both on desktop and mobile browsers. But some less capable users find the site small and fiddly on some of their mobile devices. The ability to pinch zoom (which I have not disabled) is a help, but it means constant zooming in and out to navigate.
I have tried solutions involving CSS transform: scale(...) and HTML <meta name="viewport" ...> and altering these from JavaScript. But these all seem to have a 'pinch zoom' effect, not the page zoom I am after. Also transform: scale(...) causes problems with js based/pixelbased interaction types such as draggable which I use.
I have also looked at altering CSS font sizes from JavaScript. But this only works for text, not the images, <div>s etc..
Apologies for answering my own question, but after a lot of tinkering, I found a way that works for me and seems to work on most web sites, so I thought it was worth sharing:
function zoom(scale) {
document.body.style.transform = "scale(" + scale + ")";
document.body.style.transformOrigin = "top left";
document.body.style.width = (100 / scale) + "%";
document.body.style.height = (100 / scale) + "%";
};
zoom(1.25);
The trick is to scale up the body with a scale transform, but then reduce the height and width. Reducing the height and width causes it to re-flow and keep the transformed content on the screen.
I tested the above code by pasting it into the console of Chrome Firefox and IE on several popular websites. It seems to perfectly re-scale amazon.com and stackoverflow.com, but not gmail. My own web app needed the patches described below.
Fuller solution with patches for jQuery:
With the above solution (and after pinch zoom), issues occur when JavaScript tries to measure pixel positions and use them to position other elements. This is because functions like getBoundingClientRect() returns coordinates multiplied by scale. If you use jQuery .height(), .width(), offset() etc. you get the same issue; all jQuery docs says, "dimensions may be incorrect when the page is zoomed by the user".
You can fix jQuery methods like .width() so deliver values as they would be if were viewing it with scale = 1.
Edit since jQuery 3.2.0: height(), width(), etc. have been fixed and do not require the patch shown below. But offset() still needs the patch and if you use $(window).height() or width() to find the size of the view-port you will need to divide by scale.
var zoom = (function () {
var scale = 1, recurLev = 0;
function alter(fn, adj) {
var original = $.fn[fn];
$.fn[fn] = function () {
var result;
recurLev += 1;
try {
result = original.apply(this, arguments);
} finally {
recurLev -= 1;
}
if (arguments.length === 0 && recurLev === 0) {
result = adj(result);
}
return result;
};
}
function scalePos(n) { return n / scale; }
/* Not needed since jQuery 3.2.0
alter("width", scalePos);
alter("height", scalePos);
alter("outerWidth", scalePos);
alter("outerHeight", scalePos);
alter("innerWidth", scalePos);
alter("innerHeight", scalePos);
*/
alter("offset", function (o) { o.top /= scale; o.left /= scale; return o; });
return function (s) {
scale = s;
document.body.style.transform = "scale(" + scale + ")";
document.body.style.transformOrigin = "top left";
document.body.style.width = (100 / scale) + "%";
document.body.style.height = (100 / scale) + "%";
};
}());
zoom(1.25);
The only other issue I found was in code (like dragging and drawing etc) that uses positions from events like mousedown, touchstart, mousemove, touchmove etc. I found you had to scale pageX and pageY by dividing them by scale.
If you are okay with replicating a "pinch zoom", then you can use the widely supported document.body.style.zoom property.
Try running this in your console:
document.body.style.zoom = 2;
Hi you can try this
css:
div {
margin: 150px;
width: 200px;
height: 100px;
background-color: yellow;
border: 1px solid black;
border: 1px solid black;
-ms-transform: scale(2,3); /* IE 9 */
-webkit-transform: scale(2,3); /* Safari */
transform: scale(2,3); /* Standard syntax */
}
Html:
<div>
This div element is two times of its original width, and three times of its original height.
</div>
Change font size on everything? So basically, every font size you define would need to use em as its units (intstead of px for example) so that it become a fraction of the default font.
Then you can set the body's font size (in px) to change the size of all the fonts.
function zoomPage(amount) {
var currentSize = Number(window.getComputedStyle(document.body, null).getPropertyValue('font-size').match(/\d+/));
console.log(Number(currentSize), amount, (currentSize + amount));
document.body.style.fontSize = (currentSize + amount) + 'px';
}
body {
font-size: 20px;
font-family: sans-serif;
max-width: 300px;
}
#smaller {
font-size: 0.5em;
}
.noresize {
font-size: 20px;
}
<button class="noresize" onclick="zoomPage(1)">+</button><button class="noresize" onclick="zoomPage(-1)">-</button>
<h1>I am big text</h1>
<p>I am <i>smaller</i> text</p>
<p id="smaller">I am even smaller text, even though I am also a paragraph</p>

make div 100% of browser height depending on length of content

I have 2 divs, a navigation and a main content in a bootstrap grid system. The length of either can vary depending on amount of content. I need them both styled to fill 100% of the browser window IF neither has the content to reach the bottom naturally. But if at least one of the divs has more content than the length of the browser window, I need to be able to scroll down the page with the styles of both divs remaining in tact and both have a height of the longer of the 2 divs.
I'm currently using a javascript resize function which seems to work but not in the case where neither div is long enough to fill the height of the browser window. Any suggestions?
HTML
<div class="row">
<div id="nav" class="col-xs-2">
Variable Height Navigation
</div>
<div id="main" class="col-xs-10">
Variable Height Content
</div>
</div>
Javascript
function resize() {
var h = (document.height !== undefined) ? document.height : document.body.offsetHeight;
document.getElementById("nav").style.height = h + "px";
}
resize();
window.onresize = function () {
resize();
};
I am trying to understand you question, and if I'm correct what you are looking for is:
Both divs need to be equally high
They need be at least the height of the screen
They need to take the height of the highest div
So let's try to achieve this goal as simply as possible:
var main = document.getElementById('main');
var nav = document.getElementById('nav');
function resize(){
var highest;
// Set the divs back to autosize, so we can measure their content height correctly.
main.style.height = 'auto';
nav.style.height = 'auto';
// Find the highest div and store its height.
highest = main.clientHeight > nav.clientHeight
? main.clientHeight
: nav.clientHeight;
// Check if the highest value is the div or the window.
highest = highest > window.innerHeight
? highest
: window.innerHeight;
// Assign the newly found value
main.style.height = highest + 'px';
nav.style.height = highest + 'px';
}
resize();
// Also, you don't need to wrap it in a function.
window.resize = resize;
// However, better would be:
window.addEventListener('resize', resize, false);
#main, #nav {
width: 100%;
height: auto;
}
#main { background: red; }
#nav { background: green; }
<div id="main"></div>
<div id="nav"></div>
Now, If you aren't bothered with the actual sameness in heiught of both divs but just want them to at least be one screenful, you should consider using CSS:
html, body { height: 100%; }
#nav, #main { min-height: 100%; }
I think that is the better solution (no Javascript!) and sort-of does what you want, bar the fact that you won't have to equally high div elements. However, you would barely notice it as each will at least fill the page.
You could try using viewport height:
For example:
#nav {
min-height: 100vh;
}
#main {
min-height: 100vh;
}
See Bootply.
This will also remove the need for JavaScript.

Programmatically Resizing Divs

I'm working on an HTML5 browser game that can be divided into 3 parts: two UI panels on the left and right of a center set of square canvases for the playing surface. The three panels need to be horizontally aligned, and the total game needs to keep an aspect ratio of 16:9. The left and right panels should be of equal widths, and all three panels must be of equal height. I have specified a minimum width and height inside a resize() function called when an onresize event is detected.
Currently, each panel is a div, and all three are contained inside a section. Right now, the section isn't necessary, but I want to keep the game separated from extra content at the bottom of the screen that I might choose to add later.
The CSS style is as follows:
* {
vertical-align: baseline;
font-weight: inherit;
font-family: inherit;
font-style: inherit;
font-size: 100%;
border: 0 none;
outline: 0;
padding: 0;
margin: 0;
}
#gameSection {
white-space: nowrap;
overflow-x: hide;
overflow-y: hide;
}
#leftPanel, #centerPanel, #rightPanel {
display: inline-block;
}
#leftPanel {
background-color: #6495ed;
}
#centerPanel {
background-color: #e0ffff;
}
#rightPanel {
background-color: #b0c4de;
Right now, I have set the background color of each div just to show me when I'm correctly setting the size of each div.
The body of my HTML document is as follows:
<body onresize="resize()">
<section id="gameSection">
<div id="leftPanel">Left Panel.</div>
<div id="centerPanel">Center Panel.</div>
<div id="rightPanel">Right Panel.</div>
</section>
</body>
And finally, my resize() function (I created a separate function for resizing the game in case I add more elements below later):
function resize() {
var MIN_GAME_WIDTH = 800;
var MIN_GAME_HEIGHT = 450;
var GAME_ASPECT_RATIO = 16 / 9;
var width = window.innerWidth;
var height = window.innerHeight;
var gWidth, gHeight;
if(width < MIN_GAME_WIDTH || height < MIN_GAME_HEIGHT) {
gWidth = MIN_GAME_WIDTH;
gHeight = MIN_GAME_HEIGHT;
}
else if ((width / height) > GAME_ASPECT_RATIO) {
<!-- width is too large for height -->
gHeight = height;
gWidth = height * GAME_ASPECT_RATIO;
}
else {
<!-- height is too large for width -->
gWidth = width;
gHeight = width / GAME_ASPECT_RATIO;
}
resizeGame(gWidth, gHeight, GAME_ASPECT_RATIO);
}
function resizeGame(var gWidth, var gHeight, var aspectRatio) {
var gSection = document.getElementById("gameSection");
var lPanel = document.getElementById("leftPanel");
var cPanel = document.getElementById("centerPanel");
var rPanel = document.getElementById("rightPanel");
gSection.height = gHeight;
gSection.width = gWidth;
<!-- should the below be taken care of in the CSS? -->
lPanel.height = gHeight;
cPanel.height = gHeight;
rPanel.height = gHeight;
cPanel.width = cPanel.height;
lPanel.width = (gWidth - cPanel.width) / 2;
rPanel.width = lPanel.width;
}
I've tried a number of different commands to resize the divs, but it just isn't working for me. When I try adding test canvases, color appears, but the boxes still aren't the correct size. I have also considered loading an invisible background image to each div and scaling it to the desired size; however, I was able to resize my canvas using the above method before and it seemed to work just fine.
Additional Notes
While I've already had pretty good success resizing a single canvas, I don't want to use just one canvas for the game because not all parts of the UI need to be drawn at the same time.
I'm trying to keep this solely in Javascript.
I suspect that I could just use CSS to handle resizing by fixing the aspect ratio to 16:9 and using width:56.25% for the center panel and width:21.875% for the side panels, but that limits me to one aspect ratio and doesn't explain why my above script isn't working.
I can provide the entire HTML file if needed. This is what it's supposed to look like:
End Goal (without right panel)
Thank you!
UDPATE:
jsfiddle
I got it kind of working here. I made a lot of changes/minor fixes to the code before finding what was wrong (other than various syntax errors):
You were using .width and .height instead of .style.width and .style.height, and you were applying integers to these instead of strings with "px" appended to them. Both of these things are completely understandable to miss.
I also moved the onresize from the body tag into the JS, don't know why it wasn't working on jsfiddle, but this is good practice anyways.
In the future: learn how to debug JS using the console and when you ask questions, use small examples, not your entire codebase. This question could have been simplified to "How do I resize a div?" with one line of JS and one div. You also should consider not doing this specific thing in JS, and using flexbox as redbmk said.

Adjust text size dynamically within div and also responsive

I have two working JSFiddle which I want to combine and work together.
JSFiddle-1 : http://jsfiddle.net/MYSVL/3050/
window.onresize=function() {
var child = $('.artist');
var parent = child.parent();
child.css('font-size', '18px');
while( child.height() > parent.height() ) {
child.css('font-size', (parseInt(child.css('font-size')) - 1) + "px");
}
Here the text inside artist container is responsive and its stretching to maximum font size when the screen is bigger. Its also shrinking to smallest font size when screen size is smaller.
JSFiddle-2 : http://jsfiddle.net/MYSVL/3047/
function calcDivHeights() {
window.onresize=$(".artist").each(function () {
var child = $(this);
var parent = child.parent();
//child.css('font-size', '18px');
while (child.height() > parent.height()) {
child.css('font-size', (parseInt(child.css('font-size')) - 1) + "px");
}
});
}
Here the function is checking for every artist div and adjusting the font size according to the while condition but I am unable to make it responsive like my JSFiddle-1 . Once the text size is smaller it remains smaller even I make the screen bigger. I want my JSFiddle-2 to work exactly as JSFiddle-1 so that I can maintain the responsiveness of the text according to screen size.
Can someone please help me out or feel free to modify my JSFiddle-2 in order to achieve the goal.
Thanks in advance
I can't see differences between your two fiddles except for the commented child.css('font-size', '18px'), both should do the same thing.
Your second fiddle seems to not works properly because once you resize window to a smaller resolution, child becomes smaller or equal to parent. Then, when you return on bigger resolution, you call again while( child.height() > parent.height() ), but now your child height is not greater than your parent height.
I think the following will just do what you're asking for:
$(document).ready(function () {
function adjustFontSize() {
var child = $('.artist');
var parentHeight = child.parent().height();
while( child.height() > parentHeight ) {
child.css('font-size', (parseInt(child.css('font-size')) - 1) + "px");
}
while( child.height() < parentHeight ) {
child.css('font-size', (parseInt(child.css('font-size')) + 1) + "px");
}
};
adjustFontSize(); // Call it when document is ready
window.onresize = adjustFontSize; // Call it each time window resizes
});
.artist-container {
width: 20%;
height: 40px;
border: 1px solid black;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="artist-container">
<div class="artist">Audhit Audhit Audhit Audhit Audhit Audhit Audhit</div>
</div><br>
<div class="artist-container">
<div class="artist">Lorem</div>
</div><br>
I think the CSS media queries approach is so much better for making a web responsive, than calculating everything with Javascript all the time.
For example, you can think about three sizes:
Phone (lets say, 400px width)
Tablet (lets say, 800px width)
Computer (lets say, >800px width)
One way of achieving this, using the desktop first approach, would be:
/* DESKTOP */
body {
font-size: 1em;
...
}
...
/* General rules for desktop
...
/* TABLET */
#media screen and (max-width:800px and min-width:400px) {
/* Overwrite the rules you want to change */
body {
font-size: .75em;
}
...
}
/* PHONE */
#media screen and (max-width:400px) {
/* Overwrite the rules you want to change */
body {
font-size: .75em;
}
#div1 {
height: 20%;
}
...
}
In addition to this, don't forget to work with relative units (em, vw, vh, rem...) and percentages.
Here you have a really good link about responsive design.

Is there any cross-browser javascript for making vh and vw units work

Note: Ok while I was typing this question I came across this
question which suggests to use #media query but was asked back in
2011...
As you know CSS3 introduces new Viewport-percentage length units, vh and vw, which I feel are really useful for a solid responsive layout, so my question is, is there any JavaScript/jQuery alternative for this? More over apart from using it for font sizes, is it safe to use for sizing elements? Like example
div {
height: 6vh;
width: 20vh; /* Note am using vh for both, do I need to use vw for width here? */
}
Update 5: .css(property) fix
Plugins like fancyBox use .css('margin-right') to fetch the right margin of an element and .css('margin-right', '12px') to set the right margin of an element. This was broken, because there was no check if props is a string and if there are multiple arguments given. Fixed it by checking if props is a string. If so and there is multiple arguments, arguments is rewritten into an object, otherwise parseProps( $.extend( {}, props ) ) is not used.
Update 4: Plugin for responsive layouts https://github.com/elclanrs/jquery.columns (in the works)
I gave this a (long) try. First here's the CSS example: http://jsbin.com/orajac/1/edit#css. (resize the output panel). Notice that the font-size doesn't work with viewport units, at least on latest Chrome.
And here's my attempt at doing this with jQuery. The jQuery demo which works with the font as well is at http://jsbin.com/izosuy/1/edit#javascript. Haven't tested it extensively but it seems to work with most properties since it's just converting the values to pixel and then by calling the plugin on window.resize it keeps updating.
Update: Updated code to work with many browsers. Test locally if you're using anything other than Chrome because jsBin acts a bit weird with window.resize.
Update 2: Extend native css method.
Update 3: Handle window.resize event inside of the plugin so the integration is now seamless.
The gist (to test locally): https://gist.github.com/4341016
/*
* CSS viewport units with jQuery
* http://www.w3.org/TR/css3-values/#viewport-relative-lengths
*/
;(function( $, window ){
var $win = $(window)
, _css = $.fn.css;
function viewportToPixel( val ) {
var percent = val.match(/[\d.]+/)[0] / 100
, unit = val.match(/[vwh]+/)[0];
return (unit == 'vh' ? $win.height() : $win.width()) * percent +'px';
}
function parseProps( props ) {
var p, prop;
for ( p in props ) {
prop = props[ p ];
if ( /[vwh]$/.test( prop ) ) {
props[ p ] = viewportToPixel( prop );
}
}
return props;
}
$.fn.css = function( props ) {
var self = this
, originalArguments = arguments
, update = function() {
if ( typeof props === 'string' || props instanceof String ) {
if (originalArguments.length > 1) {
var argumentsObject = {};
argumentsObject[originalArguments[0]] = originalArguments[1];
return _css.call(self, parseProps($.extend({}, argumentsObject)));
} else {
return _css.call( self, props );
}
} else {
return _css.call( self, parseProps( $.extend( {}, props ) ) );
}
};
$win.resize( update ).resize();
return update();
};
}( jQuery, window ));
// Usage:
$('div').css({
height: '50vh',
width: '50vw',
marginTop: '25vh',
marginLeft: '25vw',
fontSize: '10vw'
});
I am facing this issue with the Android 4.3 stock browser (doesn't support vw,vh, etc).
The way I solved this is using 'rem' as a font-size unit and dynamically changing the < html >'s font-size with javascript
function viewport() {
var e = window, a = 'inner';
if (!('innerWidth' in window )) {
a = 'client';
e = document.documentElement || document.body;
}
return { width : e[ a+'Width' ] , height : e[ a+'Height' ] };
}
jQuery(window).resize(function(){
var vw = (viewport().width/100);
jQuery('html').css({
'font-size' : vw + 'px'
});
});
and in your css you can use 'rem' instead of px,ems,etc
.element {
font-size: 2.5rem; /* this is equivalent to 2.5vw */
}
Here's a demo of the code : http://jsfiddle.net/4ut3e/
I wrote small helper to deal with this problem. It's supported on all main browsers and uses jQuery.
Here it is:
SupportVhVw.js
function SupportVhVw() {
this.setVh = function(name, vh) {
jQuery(window).resize( function(event) {
scaleVh(name, vh);
});
scaleVh(name, vh);
}
this.setVw = function(name, vw) {
jQuery(window).resize( function(event) {
scaleVw(name, vw);
});
scaleVw(name, vw);
}
var scaleVw = function(name, vw) {
var scrWidth = jQuery(document).width();
var px = (scrWidth * vw) / 100;
var fontSize = jQuery(name).css('font-size', px + "px");
}
var scaleVh = function(name, vh) {
var scrHeight = jQuery(document).height();
var px = (scrHeight * vh) / 100;
var fontSize = jQuery(name).css('font-size', px + "px");
}
};
Simple example how to use it in HTML:
<head>
<title>Example</title>
<!-- Import all libraries -->
<script type="text/javascript" src="js/libs/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/libs/SupportVhVw.js"></script>
</head>
<body>
<div id="textOne">Example text one (vh5)</div>
<div id="textTwo">Example text two (vw3)</div>
<div id="textThree" class="textMain">Example text three (vh4)</div>
<div id="textFour" class="textMain">Example text four (vh4)</div>
<script type="text/javascript">
// Init object
var supportVhVw = new SupportVhVw();
// Scale all texts
supportVhVw.setVh("#textOne", 5);
supportVhVw.setVw("#textTwo", 3);
supportVhVw.setVh(".textMain", 4);
</script>
</body>
It's available on GitHub:
https://github.com/kgadzinowski/Support-Css-Vh-Vw
Example on JSFiddle:
http://jsfiddle.net/5MMWJ/2/
Vminpoly is the only polyfill I know of — it's under develpment but works as of this post. There are static polyfills as part of the Jquery Columns and -prefix-free projects as well.
I've just made a very ugly, but perfectly working workaround for this WITH PURE CSS (no JS needed).
I came across a CSS stylesheet full of 'vw' declarations (also for heights and top/bottom properties) that needed to be rewritten for native Android Browser (which in versions 4.3 and below does NOT support 'vw' units).
Instead of rewriting everything to percentages, that are relative to parent's width (so the deeper in DOM, the most complicated calculations), which would give me a headache even before I would reach the first { height: Xvw } declaration, I generated myself the following stylesheet:
http://splendige.pl/vw2rem.css
I guess you're all familiar with 'em' units (if not: http://www.w3schools.com/cssref/css_units.asp). After some testing I discovered that old Android Browsers (as well as all the others) perfectly support the 'rem' units, which work the same as 'em', but are relative to the ROOT element font-size declaration (in most cases, the html tag).
So the easiest way to make this work was to declare the font-size for html tag that is equal to 1% of the viewport's width, e.g. 19.2px for 1920px viewport and use a lot of media queries for the whole 1920-320px range. This way I made the 'rem' unit equal to 'vw' in all resolutions (step is 10px, but you can even try declaring html{font-size} for every 1px). Then I just batch-replaced 'vw' with 'rem' and admired the working layout on Android 4.3 native browser.
Whatsmore, you can then redeclare the font-size even for the whole body tag (in whatever units you want: px, em, pt, etc.) and it does NOT affect the 'rem' equality to 'vw' in the whole stylesheet.
Hope this helps. I know it looks kinda silly, but works like a charm. Remember: if something looks stupid, but works, it is not stupid :)
"jquery.columns" is so far the best solutions.
https://github.com/elclanrs/jquery.columns
You only need 2 lines of codes to turn "vh" into a "all-browser scale".
Declare a class in html:
<img src="example.jpg" class="width50vh" />
Then in javascript:
$('.width50vh').css({width: '50vw'});
The simplest and most elegant solution I have found is to simply make a div that has height: 1vh; and width: 1vw; and when the page loads grab those values as pixels with getBoundingClientRect(). then add a listener to the document to listen for screen resizing and update the size when screen is resized.
I save the value in pixels of the vh and vw and then whenever I need to use vh i would just say 100 * vh which would give me 100vh.
Here is a code snippet on it's implementation, my answer is in vanilla js, no need for jquery.
function getViewportUnits(){
const placeholder = document.getElementById("placeholder");
const vh = placeholder.getBoundingClientRect().height;
const vw = placeholder.getBoundingClientRect().width;
console.log({vh: vh, vw: vw});
}
#placeholder{
background: red;
height: 1vh;
width: 1vw;
}
<body onload="getViewportUnits()">
<div id="placeholder"></div>
I've published a tiny lib that eases viewport-relative dimensions usage. Keep in mind it's not a polyfill, so it requires that you apply classes on the elements you want to resize. For instance, <div class="vh10 vw30">hello</div> will fill 10% of the height and 30% of the width.
Check it out: https://github.com/joaocunha/v-unit

Categories