How to fit text in line? - html

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>

Related

Fill div with img in React

I'm trying to fill a div (black area in following screen) with an img.
But the scale of image should not change.
And when the size of the div changes according to the size of the browser, the image should be displayed by adjusting the width or adjusting the height accordingly.
The image changes dynamically, so I never know if it will be tall or long.
for example
Finally, the target is to make the image show as large as possible without changing the scale of the image.
Below is the code I developed.
<div className="asset__item">
<a className="asset__img">
<img
alt="item image"
src="/img/1.jpg"
/>
</a>
</div>
CSS
.asset__item {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
position: relative;
padding: 20px 20px 20px 20px;
width: 100%;
border-radius: 16px;
margin-top: 20px;
background: #202020;
}
.asset__item img {
width: auto;
max-width: 100%;
}
Please let me know how to fix it.
I try not to modify the styles of asset__item as much as possible.
But it's ok to add a div there instead.
You can try using object-fit :
`
img{
width: auto;
max-width: 100%;
object-fit:cover;
}
`
I could not find a way to do it using only CSS. So I directly assigned width and height to my image using JavaScript. We should handle 4 different situations:
Album picture and album screen
Album picture and portrait screen
Portrait picture and album screen
Portrait picture and portrait screen
My imgObj contains initial width and height of the image (I got them using react-image-size).
And here is the code:
const imageObj = useSelector((state) => state.imageHandling.imageObj);
const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0);
const handleImageSize = () => {
if (imageObj) {
let w = 0;
let h = 0;
const ratio = imageObj.width / imageObj.height;
const theSameTypes = () => {
w = window.innerWidth;
h = window.innerWidth / ratio;
if (h > window.innerHeight) {
h = window.innerHeight;
w = h * ratio;
}
};
if (imageObj.width > imageObj.height) {
if (window.innerWidth > window.innerHeight) {
theSameTypes(); //album picture and album screen
} else {
w = window.innerWidth; //album picture and portrait screen
h = w / ratio;
}
} else {
if (window.innerWidth > window.innerHeight) {
h = window.innerHeight; // portrait picture and album screen
w = h * ratio;
} else {
theSameTypes(); // portrait picture and portrait screen
}
}
setWidth(w);
setHeight(h);
}
};
useEffect(() => {
window.addEventListener("resize", handleImageSize);
return () => {
window.removeEventListener("resize", handleImageSize);
};
}, []);
useEffect(handleImageSize, [imageObj]);

Get element width with right unit

Is possible to get "10vw" for the element width in browser or extension.Chrome "Copy Styles" just works fine.But I wanna do it in an extension.
Source code for chrome devtools
<style>
div { width: 10em }
body div { width: 10em }
#id { width: 10vw }
</style>
<div id="dom"></div>
// if viewport width is 375px
var dom = document.getElementById('app');
var style = window.getComputedStyle(dom);
var width = style.getPropertyValue('width');
console.log(width) // 37.5px, "10vw" would be great
var element = document.getElementById('dom')
var elementWidth = getComputedStyle(element ).width
this will always return width with pixels.
hope this will be helpfull

font size relative to the size of parent

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%;
}

Do you include the scrollbar width of browsers in your media query? [duplicate]

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;
}

A4 page like layout in html

I am working on small web based application where user is presented 2-3 page long report which can be printed as PDF. I looked at different solutions on stackoverflow / internet and found somewhat working solution to printing side (contents are printed with extra margins but i need to work on that to fix it) my current problem is i am not able to display html content in browser with page like layout. I am able to show 1st page with A4 size but as soon as content goes beyond 1 page it appears as if it printed outside page, you can check the images below
How page is shown in Browser
How it's print preview look like
Here is the CSS
.A4 {
background: white;
width: 21cm;
height: 29.7cm;
display: block;
margin: 0 auto;
padding: 10px 25px;
margin-bottom: 0.5cm;
box-shadow: 0 0 0.5cm rgba(0,0,0,0.5);
}
#media print {
.page-break { display: block; page-break-before: always; }
size: A4 portrait;
}
#media print {
.noprint {display:none;}
.enable-print { display: block; }
}
I am trying to solve below problems,
Would love if all the report is shown with page like layout (additionally, if i can show pages in horizontal pagination instead of long vertical page)
No padding issues while printing, what you see is printed!
Your 2nd problem:
You have to set the body margin and padding to zero. You also need to remove box shadow, margin, width and height from the A4 class in order to print multiple pages.
.A4 {
background: white;
width: 21cm;
height: 29.7cm;
display: block;
margin: 0 auto;
padding: 10px 25px;
margin-bottom: 0.5cm;
box-shadow: 0 0 0.5cm rgba(0, 0, 0, 0.5);
overflow-y: scroll;
box-sizing: border-box;
}
#media print {
.page-break {
display: block;
page-break-before: always;
}
size: A4 portrait;
}
#media print {
body {
margin: 0;
padding: 0;
}
.A4 {
box-shadow: none;
margin: 0;
width: auto;
height: auto;
}
.noprint {
display: none;
}
.enable-print {
display: block;
}
}
Your first problem:
You could try to create a pagination feature by calculating the scrollheight, and keep removing elements from the pages untill the scollheight is smaller than the page itself.
Example: https://jsfiddle.net/tk8rwnav/31/
var max_pages = 100;
var page_count = 0;
function snipMe() {
page_count++;
if (page_count > max_pages) {
return;
}
var long = $(this)[0].scrollHeight - Math.ceil($(this).innerHeight());
var children = $(this).children().toArray();
var removed = [];
while (long > 0 && children.length > 0) {
var child = children.pop();
$(child).detach();
removed.unshift(child);
long = $(this)[0].scrollHeight - Math.ceil($(this).innerHeight());
}
if (removed.length > 0) {
var a4 = $('<div class="A4"></div>');
a4.append(removed);
$(this).after(a4);
snipMe.call(a4[0]);
}
}
$(document).ready(function() {
$('.A4').each(function() {
snipMe.call(this);
});
});
This example breaks on every element. The paragraphs don't break on words, but you can implement this, but that will get complicated very fast.
Below is a revised version of the snipMe() function to ensure elements in Page 2-n are in the original order. I also added comments.
function snipMe() {
page_count++;
if (page_count > max_pages) {
return;
}
var long = $(this)[0].scrollHeight - Math.ceil($(this).innerHeight());
var children = $(this).children().toArray(); // Save elements in this page to children[] array
var removed = [];
// Loop while this page is longer than an A4 page
while (long > 0 && children.length > 0) {
var child = children.pop(); // Remove last array element from the children[] array
$(child).detach(); // JQuery Method detach() removes the "child" element from DOM for the current page
removed.push(child); // Add element that was removed to the end of "removed" array
long = $(this)[0].scrollHeight - Math.ceil($(this).innerHeight()); // Compute current size of the page
}
// If elements were removed from the page
if (removed.length > 0) {
var rev_removed = removed.reverse(); // Reverse the order of the removed array
var a4 = $('<div class="A4"></div>'); // Start a new page
a4.append(rev_removed); // Add elements removed from last page to the new page
$(this).after(a4); // Add the new page to the document
snipMe.call(a4[0]); // Recursively call myself to adjust the remainder of the pages
}
}
By default a margin is added for printing aswell. If you click on "More settings" there is a dropdown menu for Margins. select None to remove all margins.
That way you are able to handle the margins within css.