I've been working on a website (scibowltest.github.io) in which the font-size for an element is determined by javascript. If you go in to the website, it looks fine when displayed on a laptop/desktop with the browser at full width and height. However, if you resize the window to make the width smaller, the font starts to overflow the div in which it is supposed to be contained.
The following code is for the function font-sizer, which determines how big the font-size will be.
function fontSizer(text, box, scale) {
var textID = "#" + text;
var boxID = "#" + box;
var boxHeight = $(boxID).height();
var boxWidth = $(boxID).width();
var fontSize = 0;
if (boxHeight >= boxWidth) {
fontSize = (boxWidth * scale) + "px";
} else if (boxHeight < boxWidth) {
fontSize = (boxHeight * scale) + "px";
} else {}
var textHeight = $(textID).height();
var textWidth = $(textID).width();
if (textWidth > boxWidth) {
fontSize = ((fontSize * (scale * boxWidth)) / (textWidth)) + "px";
} else {}
$(textID).css("font-size", fontSize);
}
The function works based on the smaller dimension of the div (box) containing the text. However, the last if statement tries to compensate for those situations in which the text's width is greater than the div's width to try to shrink the fontsize so that the text's width is equal to the div's width times the scale.
Obviously, from looking at the website, this last if statement isn't working. If anyone could help, I would appreciate it!
For a pure CSS solution you can use some of the new length units that are intended exactly for your usecase - different screen sizes.
Play around with vw,vh,vmin,vmax and see what gives you the best results. I personally use vmin a lot.
It requires a bit of fiddling but would eliminate the use of javascript.
Also I used <wbr> in this example (although it should not be needed) - a "word break opportunity" to additionally prevent overflowing.
div {
width: 40vmin;
font-size: 8vmin;
border: 1px solid red;
resize: both;
text-align: center;
}
p {
width: 40vw;
font-size: 8vw;
border: 1px solid red;
resize: both;
text-align: center;
}
resize the screen to see the fonts scale:
<div>Start/<wbr>Stop</div>
<p>Start/<wbr>Stop</p>
Related
And I want to get the width or distance or pixel that between the div and left side of of window/viewport.
And another width again between the div to the right side of the window.
I will use the width to create a left line and right line.
But I am poor in jQuery, I try offset but seems nothing happen.
So I back to 0 again so I didn't include fiddle here since I got nothing inside.
But I have attached with the image link as below, to explain my question.
Please help me on try to get the width, I can create the line myself.
Thank you.
var of = $(ele).offset(), // this will return the left and top
left = of.left, // this will return left
right = $(window).width() - left - $(ele).width() // you can get right by calculate
Maybe this can help you.
After all, .width() isn't the only answer, like innerWidth() or outerWidth()
There is two options
One is you can use red line as image and you can place the div over the red line.
Second one,
If you want to calculate:
Left div width = parent div width - child div offset;
Right div width = parent div width - child div offset + child div width;
var parentdiv = document.getElementById("ParentDivID");
var parentWidth = parentdiv.offsetWidth;
var childdiv = document.getElementById("childDivID");
var childWidth = childdiv.offsetLeft;
This is easier to do with POJ (plain old javascript). Get the position of the element on the screen. Then evaluate its left property. That will be the width of your left line. Then subtract its right property from the width of the screen. That will be the width of your right line.
var x = document.getElementById('myDiv').getBoundingClientRect();
var myLeftLineWidth = x.left;
var myRightLineWidth = screen.width - x.right;
For more information see this post.
If you want the width of the window instead of the screen, change screen.width to window.innerWidth. If you don't want the scrollbar, etc. to be included in the width, use document.documentElement.clientWidth. (For more info on these, see this.)
We can work out that where the box starts with .offset().
Next, we can work out where the box ends with .offset() + .width().
We now know where our box sits on the x-axis.
Now let's see what we have to the left of our box with .left which can run on our .offset().
We've now worked out how much space there is to the left and how wide our box is.
Finally, we can put what we've worked out together, we can get the page width $(window).width() and minus what there is to the left of our box (stage 2) and the width of our box (stage 1) and that will only leave what is to the right of our box.
That's the theory anyway now let's have a look at some code. You'll see I'm working out all the bits from the theory and then adding some visual representation.
calcSizes = function() {
var boxPos = $(".box").offset(),
toLeft = boxPos.left,
toRight = $(window).width() - ($(".box").width() + toLeft);
$(".left").width(toLeft + "px");
$(".right").width(toRight + "px");
console.log("Right: " + toRight + "px");
console.log("Left: " + toLeft + "px");
console.log("Width: " + $(".box").width() + "px");
console.log(
$(window).width() + "px = " +
toRight + "px + " +
toLeft + "px + " +
$(".box").width() + "px"
);
console.log(" ");
}
calcSizes();
body {
margin: 0
}
.box,
.indicator {
padding: 10px 0;
text-align: center
}
.box {
width: 100px;
background: #FF5722;
margin-left: 60%
}
.indicator {
background: repeating-linear-gradient( 45deg, #F44336, #F44336 10px, #D32F2F 10px, #D32F2F 20px);
overflow: hidden;
transform: translatey(-100%);
opacity: .8
}
.left {
float: left
}
.right {
float: right
}
button {
position: fixed;
top: 55px;
left: 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">BOX</div>
<div class="left indicator">
LEFT
</div>
<div class="right indicator">
RIGHT
</div>
<button onclick="calcSizes()">
Recalculate
</button>
Hope this makes sense and helps you with your project.
You can do that with JavaScript, no need for jQuery:
var mydiv = document.getElementById('mydiv');
var offset = mydiv.getBoundingClientRect();
var offsetRight = document.documentElement.clientWidth - offset.right;
var offsetLeft = offset.left;
JSFiddle
I have created a magnifier in pure js. What I discovered in needing to translate the mouse position of a div relative to its parents is that in calculating the top for the overlaying magnifier div, the offsetTop works differently than the offsetLeft. After adjusting for what should be the top, I need to subtract the whole container div's offsetHeight.
The line in the code in question is this:
magnifier.style.top = yPosition - container.offsetHeight + "px";
Why do I need to subtract container.offsetHeight?
I know I've read something regarding this, but can't find it.
Disclaimers This code is working. I am asking so I (and those following) can understand how the box model works.
I know there are jQuery alternatives that are more cross browser reliable. I like to code it myself so that I can learn how it all works. If you see something which is not compatible for a modern browser, feel free to comment.
Lastly, For anyone using this, I removed code from this example to adjust for transforms. For example, if the wrapper has a transform: translate(-50%, 0); to center the wrapper horizontally, you will need to add the resulting amount of the translation (which translates to the wrapper's left position) back into the calculation.
I have created a jsfiddle here. I left more comments in the Fiddle as to methodology if anyone is interested.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="../css/ms.js"></script>
<style type="text/css">
/********************/
body {
background-color: #FFF;
margin-left: 30px;
margin-top: 10px;
}
.wrapper {
position: absolute;
left: 100px;
}
#container {
width: 527px;
height: 450px;
border: 5px black solid;
overflow: hidden;
background-color: #F2F2F2;
cursor: pointer;
}
#image {
width: 527px;
height: 450px;
}
#magnifier {
width: 250px;
height: 250px;
overflow:hidden;
position:relative;
z-index: 1000;
border: solid 1px;
}
#magnifier img {
position: absolute;
}
</style>
</head>
<body>
<div class="wrapper" id="wrapper">
<div id="container">
<img id="image" src="../docs/grade-2/jpg/g2-bb-saints-francis.jpg">
<div id="magnifier" class="magnifier">
<img id="imagecopy">
</div>
<br>
</div>
<input type="button" value="Zoom" onClick="initmagnifier('magnifier', 'image', 'imagecopy');"><br>
</div>
<script>
function initmagnifier(magnifier, image, imagecopy){
var magnifier = document.getElementById("magnifier");
var container = document.getElementById("container");
var wrapper = document.getElementById("wrapper");
var img = document.getElementById(image);
var imgcopy = document.getElementById(imagecopy);
var zoom = 2;
container.addEventListener("mousemove",
function(e){
movemagnifier(e, img, imgcopy, magnifier, container, wrapper, zoom)
}, false);
var src = img.src;
imgcopy.src = src;
var src2 = imgcopy.src;
imgcopy.height = img.height * zoom;
imgcopy.width = img.width * zoom ;
}
function movemagnifier(e, img, imgcopy, magnifier, container, wrapper, zoom) {
// to get the left & top of the magnifier
// position needs to be adjusted for WRAPPER & CONTAINER top and left
// gets the top and left of the container
var containerPosition = getPosition(e.currentTarget);
// adjust out the CONTAINER's top / left
// Then takes 1/2 the hight of the MAGNIFIER and subtracts it from the MOUSE position to center MAGNIFIER around the MOUSE cursor
var xPosition = e.clientX - containerPosition.x - (magnifier.clientWidth / 2);
var yPosition = e.clientY - containerPosition.y - (magnifier.clientHeight / 2);
magnifier.style.left = xPosition + "px";
magnifier.style.top = yPosition - container.offsetHeight + "px";
// Adjust for zoom
// adjust the MAGNIFIER's top/left at an equal pace to the zoom amount
var yTravel = (e.clientY - containerPosition.y ) * (zoom - 1);
var yimgPosition = -(yPosition - container.clientTop + yTravel);
imgcopy.style.top = yimgPosition + "px";
var xTravel = (e.clientX - containerPosition.x) * (zoom - 1); // * 1.5
var ximgPosition = -(xPosition + xTravel);
imgcopy.style.left = ximgPosition + "px";
console.log('****');
console.log(e.clientY); // MOUSE POSTION
console.log(containerPosition.y);
console.log(wrapper.offsetTop);
console.log(wrapper.clientHeight);
console.log(container.offsetTop);
console.log(container.clientHeight);
console.log(yPosition);
console.log(container.offsetHeight);
console.log(magnifier.style.top);
}
function getPosition(element) {
var xPosition = 0;
var yPosition = 0;
// element is the CONTAINER
// This calculates the postion of the element (CONTAINER) TOP & LEFT relative to ALL parents
while (element) {
// if transform: translate in place for x and y,
// add it back as it skews the offsetLeft offsetTop values by the translate amount
xPosition += ((element.offsetLeft) - element.scrollLeft);
yPosition += ((element.offsetTop) - element.scrollTop);
element = element.offsetParent;
}
return { x: xPosition, y: yPosition };
}
</script>
</body>
</html>
It took me longer than I care to admit, but I have found the reason. In your fiddle you position the #magnifier-element relative, which means you have to move it from its 'natural' position, which is below the image inside the container.
So with every move you have to compensate for this, by pulling the #magnifier to the top/left position of the container, the left position already matches, but the 'natural' top position of the #magnifier is the full height of the container, as you calculate from the top/left position of the #container, you need to subtract the #container height.
A simple fix is to add position: relative to the #container and change position: relative on the #magnifier to position: absolute.
This will give you the expected coordinate system for the #magnifier as top: 0; left: 0 for the absolute positioned element is the top left corner of the its relative parent (the first positioned parent element, in this case #container).
a working example without the need to to subtract container.offsetHeight.
While I'm at it, you may want to look into the Element.getBoundingClientRect function, as you can get all information you need to determine the position in a single call.
My objective is to make my text take as much of the space within a container as possible without overflow. If there are only a few words, they would have a very large font size, inversely if there are several words it would result in a smaller size that still takes as much of the containers area as possible.
So if I had this HTML
<div id="container">
<h1 class="textFill">Make this fit as large as possible in the container</h1>
</div>
and the container was 400 by 300px
#container {
width: 400px;
height: 300px;
border: 1px solid blue;
}
I would want the text to fill the entirety of that space. So far I have this script.
function textFill() {
$(".textFill").each(function() {
var
$text = $(this),
$parent = $text.parent();
var
textW = $text.width(),
parentW = $parent.width(),
ratio = parentW / textW;
var
originalSize = parseFloat($text.css('font-size')),
newSize = originalSize * (1 * ratio);
$text.css("font-size", newSize);
});
}
Here it all is in a http://jsfiddle.net/nz7h2858/41/
I would increase the font size until the element goes beyond its parent's bounds.
Then decrease the font size by one.
textFill();
$(window).resize(textFill);
function textFill() {
var tf= $('.textFill');
for(var i = 1 ; ; i++) {
tf.css('font-size', i);
if(tf.outerHeight(true) > tf.parent().innerHeight() ||
tf[0].scrollWidth > tf.width()
) {
break;
}
}
tf.css('font-size', i-1);
}
Fiddle
http://jsfiddle.net/nz7h2858/42/
This seems to be working a majority of the time. Occasionally some text will go out of bounds, but only slightly. Hopefully it's enough to get you started!
Things to notice:
.textFill {
display: inline;
}
Because h1 is a block element, it defaults to the full width of it's parent. So your ratio for width would always be 1:1.
Secondly, you need to also take into consideration the height. So:
textW = $text.width(),
textH = $text.height(),
parentW = $parent.width(),
parentH = $parent.height(),
ratio = (parentW + parentH) / (textW + textH);
I have three blocks, I want them positioned at the bottom always, regardless of the viewport height, and when there's not enough height to show all of it, I want them to hide from the bottom, NOT the top.
I tired a flexbox solution: http://jsbin.com/kutipequxe/1/edit?css,output
.. it almost works, except on low resolutions, the blocks hide from top, bottom remains visible.
I also tried another solution: http://jsbin.com/ruhigijeba/1/edit?css,output
.. well this keeps the top always visible, but just hides the bottom altogether, including the other two blocks.
I even tried a JS solution:
var vh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
var topHeight = document.getElementById('top').offsetHeight;
console.log('Viewport Height: ' + vh);
function getHeight(element) {
console.log(document.getElementsByClassName(element));
var offsetHeight = document.getElementsByClassName(element)[0].offsetHeight;
console.log('offsetHeight: ' + offsetHeight);
var marginTop = vh - (topHeight + offsetHeight);
console.log('marginTop: ' + marginTop);
document.getElementsByClassName(element)[0].style.marginTop = marginTop + "px";
}
getHeight("card-1");
getHeight("card-2");
getHeight("card-3");
... but it still hides the blocks from top!
try it with CSS media queries:
At the end of your CSS just add
#media screen and (max-height: 120px) {
div#top {
display: none;
height: 0px;
}
#main {
height: 100vh;
}
}
[edit] appearently thats not what oyu were asking for.
so... in your second jsbin example, add this to your .cards class:
position: sticky;
bottom: 0;
and to your #cards id:
overflow: hidden;
http://jsbin.com/zijedofija/1/
it does not work on chrome 35+ though: Why doesn't position: sticky work in Chrome?
my best bet would be to use a jquery plugin for chrome: https://github.com/filamentgroup/fixed-sticky
Ended up using Javascript and CSS media queries to achieve the desired results:
var vh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
var topHeight = document.getElementById('top').offsetHeight;
function getHeight(element) {
var elementHeight = document.getElementsByClassName(element)[0].offsetHeight;
var offsetTop = vh - (topHeight + elementHeight);
var cardsContainerHeight = document.getElementById('cards').offsetHeight;
if (elementHeight < cardsContainerHeight) {
document.getElementsByClassName(element)[0].style.top = offsetTop + "px";
}
}
var resize = function(event) {
getHeight("card");
}();
I am developing a bunch of small web applications that have an unknown window size as target. To solve this problem, I am developing very large layouts and scaling them according to the window size.
My solution however has an inconvenience. When I resize everything, things get a little bit out of place (mainly when scaling text) and it is noticeable. My code is very simple, everything in my page is absolutely positioned so I just get the scaling factor and apply it to all the positions and width / height of every div/img/span/input in the page. The code is as follows:
function resize()
{
var wh = $(window).height();
var h = maxHeight;
var ww = $(window).width();
var w = maxWidth;
var wProp = ww / w;
var hProp = wh / h;
if (wProp < hProp) prop = wProp;
else prop = hProp;
if (prop > 1) prop = 1;
console.log(prop);
$("div").each (applyNewSize);
$("img").each (applyNewSize);
$("span").each (applyNewSize);
$("input").each (applyNewSize);
}
//this is run when the page is loaded
function initializeSize (i)
{
this.oX = $(this).position().left;
this.oY = $(this).position().top;
this.oW = $(this).width();
this.oH = $(this).height();
if ($(this).css("font-size") != undefined)
{
this.oFS = Number($(this).css("font-size").split("px")[0]);
}
}
function applyNewSize (i)
{
if (this.oFS != undefined) $(this).css("font-size", Math.round(this.oFS * prop) + "px");
$(this).css("left", Math.round(this.oX * prop) + "px");
$(this).css("top", Math.round(this.oY * prop) + "px");
$(this).width(Math.round(this.oW * prop));
$(this).height(Math.round(this.oH * prop));
}
This problem has been tormenting me for the past week. Do you have any workaround or solution for this?
I recommend you to read about Responsive Web design.
It works putting % instead the exact pixels :
<div class="container">
<section>
THIS IS THE SECTION
</section>
</div>
CSS::
.container{
width: 80%; // 80% instead pixels
background: gainsboro;
border: 3px inset darkgrey;
height: 200px;
margin:auto;
text-align:center;
}
section{
width: 80%; // 80% instead pixels
height: 80%; // 80% instead pixels
background: darkgrey;
margin:auto;
}
Then you can use media queries as well, to reallocate the blocks or applying different styles on different widths :
example tutorial : http://css-tricks.com/css-media-queries/