I have a container which can have different sizes depending how the user moved some elements on the screen.
Inside this container there is an image and a text. The image fills out 80% of the height of the conainer and the text should fill out the other 20%.
While the height: 80% works fine for the image font-size: 20% doesn't work for the text. I can't use vm or vh since the size has nothing to do with the screen size.
I found this link that should be helpful: LINK
flexFont = function () {
var divs = document.getElementsByClassName("flexFont");
for(var i = 0; i < divs.length; i++) {
var relFontsize = divs[i].offsetWidth*0.05;
divs[i].style.fontSize = relFontsize+'px';
}
};
window.onload = function(event) {
flexFont();
};
window.onresize = function(event) {
flexFont();
};
#font-face {
font-family: "San Francisco";
font-weight: 200;
src: url("//applesocial.s3.amazonaws.com/assets/styles/fonts/sanfrancisco/sanfranciscodisplay-thin-webfont.woff2");
}
body, html {
height:100%;
width:100%;
font-family: "San Francisco";
font-weight: 200
}
.flexFont {
height:8em;
width:75%;
background-color:#eeeeee;
padding:1%;
margin: 10px;
}
.smaller {
font-size: 0.7em;
background-color:red;
width: 10em;
}
<div class="flexFont">
<h2>This is FlexText:<br>Autoscaling by DIV width</h2>
<div class='smaller'>... scaled by 0.7em</div>
</div>
<div class="flexFont">
<p>Font size scales parallel to the container width.<br>Change window size to test.<p>
</div>
Without the use of VM/VH you would need to use a combination of javascript and CSS to achieve this. The code above should help in what you are trying to achieve.
Using a percent for font-size adjusts the font based on the current font-size for the document (it doesn't adjust the font to take up a percentage of the container). Check out CSS Font-Size: em vs px vs pt vs percent.
For example:
/* current font-size for the document */
html {
font-size: 20px;
}
/* results in 4px font-size for this div */
div {
font-size: 20%;
}
Related
I want to bind text font-size with text length (in <p> with fixed width for example). Expected result is text fit in one line if it is only one word. If there are few words, it can be few lines.
I want to reduce font-size if word is too long for fixed-width line. For example, if "abc" fit in line I want to do nothing, if "abcdefg" doesn't fit in line I want to reduce text font-size
You can use a simply div setting your personal width, inside set your text, in css use
display: flex;
flex-wrap: wrap;
That way the text will respect your div width and brake line in your text when necessary
flex-wrap
Hope this answer will satisfy your question.
The resizing part, which is the most important, is creditted to Jan Küster, with "Make text fit its parent size using JavaScript" article that you can find online.
document.getElementsByTagName("input")[0].onkeyup = execute;
function execute() {
let value = document.getElementsByTagName("input")[0].value;
let words = value.split(" ");
var html = "";
for (var i = 0; i < words.length; i++) {
html += ' <div class="text-container"><span class="text">' + words[i] + '</span></div>';
document.getElementsByClassName("parent")[0].innerHTML = html;
}
resizeText({
elements: document.querySelectorAll('.text'),
step: 0.25
})
}
//
const isOverflown = ({
clientWidth,
clientHeight,
scrollWidth,
scrollHeight
}) => (scrollWidth > clientWidth) || (scrollHeight > clientHeight)
const resizeText = ({
element,
elements,
minSize = 10,
maxSize = 512,
step = 1,
unit = 'px'
}) => {
(elements || [element]).forEach(el => {
let i = minSize
let overflow = false
const parent = el.parentNode
while (!overflow && i < maxSize) {
el.style.fontSize = `${i}${unit}`
overflow = isOverflown(parent)
if (!overflow) i += step
}
// revert to last state where no overflow happened
el.style.fontSize = `${i - step}${unit}`
})
}
body {
background: #A33;
}
.parent {
margin: 2%;
width: 150px;
height: auto;
min-height: 50px;
padding: 15px;
color: white;
display: block;
}
.text-container {
width: 100%;
height: 100%;
}
.text {
font-size: 12px;
display: block;
}
<input type="text">
<div class="parent">
</div>
You could check out Bootstrap 5, they now have responsive text incorporated.
You could also use media queries that change the text size when the screen size is smaller or larger:
/* If the screen size is 601px wide or more, set the font-size of div to 80px */
#media screen and (min-width: 601px) {
div.example {
font-size: 80px;
}
}
/* If the screen size is 600px wide or less, set the font-size of <div> to 30px */
#media screen and (max-width: 600px) {
div.example {
font-size: 30px;
}
}
A final option would be to use the viewport width as the font size. Viewport is the browser window size. 1vw = 1% of viewport width. If the viewport is 50cm wide, 1vw is 0.5cm. Here's an example:
<h1 style="font-size:8vw;">Hello World</h1>
<p style="font-size:2vw;">Resize the browser window to see how the font size scales.</p>
I am having problem with css media query in Firefox. It works correct in Chrome like I made two DIVs and want a scrollbar. If I decrease the screen size of firefox upto 800px then both DIVs collapse and after some pixels media query works but that not happens in Chrome.
check this fiddle http://jsfiddle.net/RMvqC/2/
I SOLVED this issue by calling the "mqGenie" javascript in the head of my project.
Now the widths of my media queries work fine ( with the same value ) on Chrome, Safari, Firefox and IE with or without scroolbars.
This javascript Adjusts CSS media queries in browsers that include the scrollbar width in the viewport width so they fire at the intended size.
You can download it from this url:
http://stowball.github.io/mqGenie/
Firefox & Webkit based browsers render the scrollbar differently. In Firefox, MediaQuery considered width of scrollbar which is 15px with the screen width, but in Webkit based browsers it's not considered scrollbar with the screen width. So, that's why the floated DIVs are collapsed in Firefox.
I did some stuff with css may be that's help you. (check this fiddle)
html {
/* force scrollbars */
height: 101%;
}
body {
margin: 0;
padding:0;
white-space:nowrap;
}
#box1,
#box2 {
display:inline-block;
width: 400px;
height: 200px;
vertical-align:top;
white-space:normal;
}
#box1 {
background: #ce0000;
margin-right:-5px;
}
#box2 {
background: #8e0000;
}
#media screen and (max-width: 799px) {
body {
white-space:normal;
}
#box1,
#box2 {
width: 300px;
}
}
Firefox & Opera follows W3C spec which is to include scrollbar width in media queries width (the reason might be to avoid infinite loop as described in a comment here), while Webkit does not (possibly coz they think it makes no sense)
There is a workaround (I've only tested this on FF), apparently if you force scrollbar to be visible all the time, then the width will now be consistent with Webkit. Here's the code:
html
{
overflow:hidden;
height:100%;
}
body
{
position:relative;
overflow-y:scroll;
height:100%;
-webkit-overflow-scrolling:touch; /* So iOS Safari gets the inertia & rubber-band effect */
}
If you want to apply this to FF & Opera only, you can resort to CSS hacks:
/* Firefox */
#-moz-document url-prefix()
{
html
{
overflow:hidden;
height:100%;
}
body
{
position:relative;
overflow-y:scroll;
height:100%;
/*-webkit-overflow-scrolling:touch;*/
}
}
/* Opera */
x:-o-prefocus, html
{
overflow:hidden;
height:100%;
}
x:-o-prefocus, body
{
position:relative;
overflow-y:scroll;
height:100%;
}
It goes without saying, the caveat is the scrollbar will be visible at all times, which might be an okay compromise.
Play safe!
My final strategy is added 20px to the media queries and that is my default white space on the layout.
With one exception: #media (min-width: 320px) At that size a don't leave the 20px white space and include one more rule to solve minor background issues:
html body {
min-width: 320px;
}
20px is the scroll bar default width size.
FYI: https://www.sitepoint.com/rwd-scrollbars-is-chrome-better/
You can implement a solution for Firefox pretty easily by using a CSS-hack. After wrapping your content in an extra <div> add this lines to your CSS:
/* Firefox-Hack */
body, x:-moz-any-link {
overflow-x: hidden;
}
#wrapper, x:-moz-any-link {
margin: 0 -7.5px;
}
Check the jsbin (jsfiddle is down right now)
To have richer responsive experience you could add another media query: another jsbin
The CSS-hack was found at paulirish.com
This is peripherally related, but I found a way to detect which media-query the browser is actually using at any given moment, without having to muck around with scrollbar and body widths...
Basically, define a an absolutely positioned 1-x-1-pixel-sized list somewhere in your body, with a list-item for each media-query condition you want to be "watchable".
Then in each media-query definition, show/hide the corresponding list-item, and then simply check whether that item is visible from within your script.
Example:
<body>
...
<ul id="mediaQueryHelper">
<li id="desktop"></li>
</ul>
</body>
<style type="text/less">
#mediaQueryHelper {
position: absolute;
height: 1px;
width: 1px;
visibility: hidden;
top: -999px;
left: -999px;
}
#media screen and (min-width: 481px)
{
#desktop { display: inline; }
}
#media screen and (min-width: 320px) and (max-width: 480px)
{
#desktop{ display: none; }
}
</style>
<script type="text/javascript">
$(document).ready(function()
{
var _desktop = $("#desktop");
$(window).resize(function() {
console.log("media-query mode: " + _desktop.is(":visible") ? "DESKTOP" : "MOBILE");
});
});
</script>
Short Answer
If you do not want to display the scrollbar all the time, wrap your content into <div> elements etc. you can use JavaScript to add a certain value to all media queries when the scrollbar is shown.
// check whether scrollbar is visible
var isScrollbarVisible = window.innerWidth > document.documentElement.clientWidth;
// search for media rule
var mediaRule = document.styleSheets[i].cssRules[j];
// update media rule
mediaRule.media.mediaText = '..'
Long Answer
I wrote a small script which you can include on your page. It detects when the window is resized and changes all media queries if needed. The value of the css variable --replace-media-scrollbar is used as the width of the scrollbar or 15px if no value was found. This works for the media queries with, min-width, max-width, height, min-height and max-height even when they are connected using and.
JavaScript:
function* visitCssRule(cssRule) {
// visit imported stylesheet
if (cssRule.type == cssRule.IMPORT_RULE)
yield* visitStyleSheet(cssRule.styleSheet);
// yield media rule
if (cssRule.type == cssRule.MEDIA_RULE)
yield cssRule;
}
function* visitStyleSheet(styleSheet) {
try {
// visit every rule in the stylesheet
var cssRules = styleSheet.cssRules;
for (var i = 0, cssRule; cssRule = cssRules[i]; i++)
yield* visitCssRule(cssRule);
} catch (ignored) {}
}
function* findAllMediaRules() {
// visit all stylesheets
var styleSheets = document.styleSheets;
for (var i = 0, styleSheet; styleSheet = styleSheets[i]; i++)
yield* visitStyleSheet(styleSheet);
}
// collect all media rules
const mediaRules = Array.from(findAllMediaRules());
// read scrollbar width
var style = getComputedStyle(document.documentElement);
var scrollbar = style.getPropertyValue('--replace-media-scrollbar') || '15px';
// update media rules
if (scrollbar != '0px') {
var oldValue = '0px';
function updateMediaRulesScrollbar() {
var newValue = window.innerWidth > document.documentElement.clientWidth ? scrollbar : '0px';
// if value changed
if (oldValue != newValue) {
for (var i = 0, mediaRule; mediaRule = mediaRules[i]; i++) {
var regex = RegExp('\\((width|min-width|max-width|height|min-height|max-height): (calc\\([^)]*\\)|[^)]*)\\)', 'g');
var replacement = '($1: calc($2 - ' + oldValue + ' + ' + newValue + '))';
mediaRule.media.mediaText = mediaRule.media.mediaText.replace(regex, replacement);
console.log(mediaRule);
}
}
oldValue = newValue;
}
updateMediaRulesScrollbar();
window.onresize = updateMediaRulesScrollbar;
}
Optional CSS:
:root {
--replace-media-scrollbar: 15px;
}
A site I'm busy working on has a section with some very large headings. There's something I'm not sure how to handle:
The heading may be one two short or long words, e.g: "Cyprus" to "Nouvelle Zelande", and it must scale to be roughly the width of the viewport. That means "Cyprus", being shorter, will have larger individual characters than longer text than "Nouvelle Zelande".
This would be relatively easy to do with JavaScript, I think, but I'd like to go for a pure HTML/CSS solution. So: how can I scale text to fit the width of the viewport? So far, I'm stumped and not sure how to do it, myself.
Some details:
You only need to target the most recent version of each browser, which includes IE11.
You may use any and all HTML5 and CSS3 that works within those browsers.
It's okay if you make the text "Nouvelle Zelande" word-wrap, as long as the longer of the two words still roughly fits to the width available.
You may add extra elements inside/around the headings.
Note that viewport units are not a solution. Previous questions asking about this (Pure CSS to make font-size responsive based on dynamic amount of characters, Font scaling based on width of container) have answers of "use viewport units, like vw!", but that doesn't handle this scenario at all, and astute readers even pointed this out. I've even used vw in the code sample below to demonstrate its non-solution-ness. It'll size based on the viewport just fine, but won't do any sizing based on the amount of text.
Code sample
h2 {
font-family: sans-serif;
text-transform: uppercase;
font-size: 14vw;
white-space: nowrap;
overflow-x: hidden;
margin: 0;
}
<h2>Nouvelle Zelande</h2>
<h2>Australia</h2>
<h2>Cyprus</h2>
The only unit, if being used to set font size, that is relative to the size of its container, is viewport units vw/vh, which will not solve your case alone, even if the container is the same width as the viewport, since it does not calc the letter size to fit into the container.
The closest non-script solution I can come up with is to use the CSS element counter trick, and wrap each letter in a span
The 130vw I set here, worked best for the given font, though this might need to be adjusted based on which font family is being used.
h2 {
display: inline-block;
font-family: sans-serif;
text-transform: uppercase;
white-space: nowrap;
overflow-x: hidden;
margin: 0;
}
/* 1 letter */
h2 span:first-child:nth-last-child(1) {
font-size: 130vw;
}
/* skipped 2-5 in this demo */
/* 6 letters */
h2 span:first-child:nth-last-child(6),
h2 span:first-child:nth-last-child(6) ~ span {
font-size: calc(130vw / 6);
}
/* skipped 7-14 in this demo */
/* 15 letters */
h2 span:first-child:nth-last-child(15),
h2 span:first-child:nth-last-child(15) ~ span {
font-size: calc(130vw / 15);
}
<h2><span>N</span><span>o</span><span>u</span><span>v</span><span>e</span><span>l</span><span>l</span><span>e</span> <span>Z</span><span>e</span><span>l</span><span>a</span><span>n</span><span>d</span><span>e</span></h2><br>
<h2><span>C</span><span>y</span><span>p</span><span>r</span><span>u</span><span>s</span></h2>
Here is the same concept using a script, and without the span's
(function (d,t) {
window.addEventListener("resize", throttler, false);
window.addEventListener("load", throttler(), false); /* run once on load to init */
function throttler() {
if ( !t ) {
t = setTimeout(function() {
t = null;
keepTextFit(d.querySelectorAll('h2'));
}, 66);
}
}
function keepTextFit(el) {
var f = el[0].getAttribute("data-font");
for (var i = 0; i < el.length; i++) {
var c = el[i].textContent.split('').length;
el[i].style.cssText =
'font-size: calc(' + f + ' / ' + c + ')';
}
}
})(document,null);
h2 {
display: inline-block;
font-family: sans-serif;
text-transform: uppercase;
white-space: nowrap;
overflow-x: hidden;
margin: 0;
}
<h2 data-font="130vw">Nouvelle Zelande</h2>
<h2>Australia</h2>
<h2>Cyprus</h2>
Note, since resize events can fire at a high rate, the throttler is used to reduced the rate so the handler doesn't execute expensive operations such as DOM modifications too often.
If you want to make a perfect fit, check this post: fit-text-perfectly-inside-a-div
If you are looking to use a plugin there's
http://fittextjs.com/
wich can do that for you
I create a website template but when I set the size, my website breaks.
My resolution is 1600x900, and when I open template on another monitor with another size , my website breaks.
The code:
* {
font-family: 'PT Sans', sans-serif;
width: 1600px;
height: auto;
}
My breaks website:
My deffault website without width and height
* in CSS is a wildcard. Therefore, when you set
* { width:1600px; }
you set every element in the page to a width of 1600px. Instead, set just the body:
body { width:1600px; }
or create a <div> with a specific ID to encapsulate your web page:
div#main { width:1600px; }
I am having problem with css media query in Firefox. It works correct in Chrome like I made two DIVs and want a scrollbar. If I decrease the screen size of firefox upto 800px then both DIVs collapse and after some pixels media query works but that not happens in Chrome.
check this fiddle http://jsfiddle.net/RMvqC/2/
I SOLVED this issue by calling the "mqGenie" javascript in the head of my project.
Now the widths of my media queries work fine ( with the same value ) on Chrome, Safari, Firefox and IE with or without scroolbars.
This javascript Adjusts CSS media queries in browsers that include the scrollbar width in the viewport width so they fire at the intended size.
You can download it from this url:
http://stowball.github.io/mqGenie/
Firefox & Webkit based browsers render the scrollbar differently. In Firefox, MediaQuery considered width of scrollbar which is 15px with the screen width, but in Webkit based browsers it's not considered scrollbar with the screen width. So, that's why the floated DIVs are collapsed in Firefox.
I did some stuff with css may be that's help you. (check this fiddle)
html {
/* force scrollbars */
height: 101%;
}
body {
margin: 0;
padding:0;
white-space:nowrap;
}
#box1,
#box2 {
display:inline-block;
width: 400px;
height: 200px;
vertical-align:top;
white-space:normal;
}
#box1 {
background: #ce0000;
margin-right:-5px;
}
#box2 {
background: #8e0000;
}
#media screen and (max-width: 799px) {
body {
white-space:normal;
}
#box1,
#box2 {
width: 300px;
}
}
Firefox & Opera follows W3C spec which is to include scrollbar width in media queries width (the reason might be to avoid infinite loop as described in a comment here), while Webkit does not (possibly coz they think it makes no sense)
There is a workaround (I've only tested this on FF), apparently if you force scrollbar to be visible all the time, then the width will now be consistent with Webkit. Here's the code:
html
{
overflow:hidden;
height:100%;
}
body
{
position:relative;
overflow-y:scroll;
height:100%;
-webkit-overflow-scrolling:touch; /* So iOS Safari gets the inertia & rubber-band effect */
}
If you want to apply this to FF & Opera only, you can resort to CSS hacks:
/* Firefox */
#-moz-document url-prefix()
{
html
{
overflow:hidden;
height:100%;
}
body
{
position:relative;
overflow-y:scroll;
height:100%;
/*-webkit-overflow-scrolling:touch;*/
}
}
/* Opera */
x:-o-prefocus, html
{
overflow:hidden;
height:100%;
}
x:-o-prefocus, body
{
position:relative;
overflow-y:scroll;
height:100%;
}
It goes without saying, the caveat is the scrollbar will be visible at all times, which might be an okay compromise.
Play safe!
My final strategy is added 20px to the media queries and that is my default white space on the layout.
With one exception: #media (min-width: 320px) At that size a don't leave the 20px white space and include one more rule to solve minor background issues:
html body {
min-width: 320px;
}
20px is the scroll bar default width size.
FYI: https://www.sitepoint.com/rwd-scrollbars-is-chrome-better/
You can implement a solution for Firefox pretty easily by using a CSS-hack. After wrapping your content in an extra <div> add this lines to your CSS:
/* Firefox-Hack */
body, x:-moz-any-link {
overflow-x: hidden;
}
#wrapper, x:-moz-any-link {
margin: 0 -7.5px;
}
Check the jsbin (jsfiddle is down right now)
To have richer responsive experience you could add another media query: another jsbin
The CSS-hack was found at paulirish.com
This is peripherally related, but I found a way to detect which media-query the browser is actually using at any given moment, without having to muck around with scrollbar and body widths...
Basically, define a an absolutely positioned 1-x-1-pixel-sized list somewhere in your body, with a list-item for each media-query condition you want to be "watchable".
Then in each media-query definition, show/hide the corresponding list-item, and then simply check whether that item is visible from within your script.
Example:
<body>
...
<ul id="mediaQueryHelper">
<li id="desktop"></li>
</ul>
</body>
<style type="text/less">
#mediaQueryHelper {
position: absolute;
height: 1px;
width: 1px;
visibility: hidden;
top: -999px;
left: -999px;
}
#media screen and (min-width: 481px)
{
#desktop { display: inline; }
}
#media screen and (min-width: 320px) and (max-width: 480px)
{
#desktop{ display: none; }
}
</style>
<script type="text/javascript">
$(document).ready(function()
{
var _desktop = $("#desktop");
$(window).resize(function() {
console.log("media-query mode: " + _desktop.is(":visible") ? "DESKTOP" : "MOBILE");
});
});
</script>
Short Answer
If you do not want to display the scrollbar all the time, wrap your content into <div> elements etc. you can use JavaScript to add a certain value to all media queries when the scrollbar is shown.
// check whether scrollbar is visible
var isScrollbarVisible = window.innerWidth > document.documentElement.clientWidth;
// search for media rule
var mediaRule = document.styleSheets[i].cssRules[j];
// update media rule
mediaRule.media.mediaText = '..'
Long Answer
I wrote a small script which you can include on your page. It detects when the window is resized and changes all media queries if needed. The value of the css variable --replace-media-scrollbar is used as the width of the scrollbar or 15px if no value was found. This works for the media queries with, min-width, max-width, height, min-height and max-height even when they are connected using and.
JavaScript:
function* visitCssRule(cssRule) {
// visit imported stylesheet
if (cssRule.type == cssRule.IMPORT_RULE)
yield* visitStyleSheet(cssRule.styleSheet);
// yield media rule
if (cssRule.type == cssRule.MEDIA_RULE)
yield cssRule;
}
function* visitStyleSheet(styleSheet) {
try {
// visit every rule in the stylesheet
var cssRules = styleSheet.cssRules;
for (var i = 0, cssRule; cssRule = cssRules[i]; i++)
yield* visitCssRule(cssRule);
} catch (ignored) {}
}
function* findAllMediaRules() {
// visit all stylesheets
var styleSheets = document.styleSheets;
for (var i = 0, styleSheet; styleSheet = styleSheets[i]; i++)
yield* visitStyleSheet(styleSheet);
}
// collect all media rules
const mediaRules = Array.from(findAllMediaRules());
// read scrollbar width
var style = getComputedStyle(document.documentElement);
var scrollbar = style.getPropertyValue('--replace-media-scrollbar') || '15px';
// update media rules
if (scrollbar != '0px') {
var oldValue = '0px';
function updateMediaRulesScrollbar() {
var newValue = window.innerWidth > document.documentElement.clientWidth ? scrollbar : '0px';
// if value changed
if (oldValue != newValue) {
for (var i = 0, mediaRule; mediaRule = mediaRules[i]; i++) {
var regex = RegExp('\\((width|min-width|max-width|height|min-height|max-height): (calc\\([^)]*\\)|[^)]*)\\)', 'g');
var replacement = '($1: calc($2 - ' + oldValue + ' + ' + newValue + '))';
mediaRule.media.mediaText = mediaRule.media.mediaText.replace(regex, replacement);
console.log(mediaRule);
}
}
oldValue = newValue;
}
updateMediaRulesScrollbar();
window.onresize = updateMediaRulesScrollbar;
}
Optional CSS:
:root {
--replace-media-scrollbar: 15px;
}