Overflow scrolling on dynamically moving elements - javascript

var block = document.getElementById('block')
function myFunct() {
block.style.transform = 'translateX(-400px)'
}
.container {
position:relative;
width:400px;
height:150px;
margin:auto;
background-color: blue;
overflow:scroll;
}
#block {
position:absolute;
height:25px;
width:100%;
left:50%;
bottom:50%;
overflow: scroll;
background-color: yellow;
border:1px solid black;
align-self: flex-end;
}
<div class="container">
<div id="block"></div>
<button onclick='myFunct()'>CLICK</button>
</div>
In my example the block overflows the right side of the container and overflow is set to scroll. So you can scroll the right side and see the rest of the block. Then when I run the function, the block moves so it's overflowing the left side of the container. However it does not adjust to allow for scrolling left to see the rest of the block. What is the solution to allow for scrolling of other sides after functions are ran and blocks are moved to overflow those different sides.

Based on this, a the solution can be sort of 'hack' like this:
var block = document.getElementById('block')
function myFunct() {
document.getElementsByClassName('container')[0].dir = 'rtl';
block.style.transform = 'translateX(-400px)'
}
.container {
position:relative;
width:400px;
height:150px;
margin:auto;
background-color: blue;
overflow:scroll;
}
#block {
position:absolute;
height:25px;
width:100%;
left:50%;
bottom:50%;
overflow: scroll;
background-color: yellow;
border:1px solid black;
align-self: flex-end;
}
<div class="container">
<div id="block"></div>
<button onclick='myFunct()'>CLICK</button>
</div>
Thanks to #TemaniAfif that point me.

The real problem at hand is that the css property transform will only trigger a repaint on the Composite Layer, this was an optimization decision made to facilitate animations without triggering repaints on the Layout Layer . To trigger an entire layout repaint you should use a layout property like left or right:
Example:
function myFunct() {
block.style.left = '0px'
}
Also the reason you are getting the scrollbar on initial load is because you have:
#block {
...
left: 50%
...
}
More here on Compositor-Only Properties
Edit:
Although the above is true, switching to 'style.left' will still not cut it
because block level elements have a default content flow direction of left to right or in css direction: ltr so this means you'll need to modify the content direction as well which should cancel out the need to use style.left. See below:
var block = document.getElementById('block')
var container = document.querySelector('.container')
function myFunct() {
block.style.transform = 'translateX(-400px)'
container.style.direction = 'rtl'
}
.container {
position:relative;
width:400px;
height:150px;
margin:auto;
background-color: blue;
overflow:scroll;
}
#block {
position:absolute;
height:25px;
width:100%;
left:50%;
bottom:50%;
overflow: scroll;
background-color: yellow;
border:1px solid black;
}
<div class="container">
<div id="block"></div>
<button onclick='myFunct()'>CLICK</button>
</div>

Is it important where the yellow block shifts and gets positioned? if you just set the #block width to allow for the extra 400px with width: calc(100% + 400px) then you can see it with overflow after calling the function.
var block = document.getElementById('block')
function myFunct() {
block.style.transform = 'translateX(-400px)'
}
.container {
position: relative;
width: 400px;
height: 150px;
margin: auto;
background-color: blue;
overflow: scroll;
}
#block {
position: absolute;
height: 25px;
width: calc(100% + 400px);
left: 50%;
bottom: 50%;
overflow: scroll;
background-color: yellow;
border: 1px solid black;
align-self: flex-end;
}
<div class="container">
<div id="block"></div>
<button onclick='myFunct()'>CLICK</button>
</div>

This is what I came up with. My solution applies to my use which is to have a have a line of text run across the page right to left and being able to scroll left to see the parts of the sentence that eventually overflow. The #fill div lets the entire wrapper be scrollable rather than just the span. There's a way to do it with two divs using "line-height = (size of container)" but I figured that would lead to future problems so I avoided. The key to my way was the "outer.scrollLeft += outer.scrollWidth" within the function. There's a more fluid way of doing this as my way is choppy by moving the entire span element left which is what my original question was pointed towards but ultimately not how I did it. Meshu's solution also worked in application to the question I asked. "Direction:rtl" also allows for a solution.
var inset = document.getElementById('inset')
var fill = document.getElementById('fill')
var text = 'There was a lamb who had a cow and a farmer was involved and then you make a moo sound and yell BINGO and that is how the song goes.'; /*Obviously you can change this jibberish */
var words = text.split(" ") /* breaking the text into an array of each word */
var i = 0
var timer = 5; /*How long the text will take to run through in seconds*/
var wordTime = (timer / words.length) * 1000; /* Time before the next word takes to the screen. As of this code, all words have equal time */
var myVar = setInterval(myFunct, wordTime);
function myFunct() {
if (i == words.length) {
clearInterval(myVar); /* Stops running when all words are passed through */
} else {
inset.innerHTML += " " + words[i];
}
i++
let outer = fill
outer.scrollLeft += outer.scrollWidth; /*important */
}
#wrapper {
position: absolute;
display: flex;
height: 100px;
width: 100%;
min-width: 100%;
max-width: 100%;
left: 0;
right: 0;
bottom: 0;
align-items: center;
text-align: right;
color: whitesmoke;
font-family: sans-serif;
font-size: 200%;
background-color: rgba(0, 0, 0, 0.7);
}
#fill {
display: flex;
width: 100%; /*You can change this to change how much of container the text overtakes */
height: 100%;
max-width: 100%;
align-items: center;
overflow: auto;
}
#inset {
padding-left:5px;
white-space: nowrap;
margin-left:auto;
}
<div id='wrapper'>
<div id='fill'>
<span id='inset'></span>
</div>
</div>
.

Related

How to set element to grow horizontally instead of breaking to a new line?

I'm facing problem with breaking the line on website. What do I mean?
HTML code
<main class="clearfix">
<div class="first"></div>
<div class="second"></div>
<div class="third"></div>
</main>
<button>Add</button>
With such HTML code I'd like to have:
fixed height on main element (for example 80vh)
fixed height for all the elements first and third 40vh + second 80vh
fixed width for first and third element 50vw
fluid width for second element - but this is main problem - second element has to be in the same place and grow horizontally (to create scroll on the bottom of the site)
Please find my codepen
I've added button that'll add pixels to second element - but it destroys my website.
I'm not sure if flexbox is better than floats.
I'll appreciate any tip.
Here is the snippet:
let counter = 0;
document.querySelector("button").addEventListener("click", function() {
document.querySelector(".second").style.width = `calc(50% + ${counter}px)`;
console.log(counter);
counter++;
});
* {
padding: 0;
margin: 0;
}
main {
max-height: 80vh;
}
.first,
.third {
height: 40vh;
width: 50vw;
background-color: black;
float: left;
}
.third {
background-color: red;
}
.second {
height: 80vh;
width: 50%;
float: right;
background-color: blue;
}
.clearfix::after {
content: "";
display: table;
clear: both;
}
<main class="clearfix">
<div class="first"></div>
<div class="second"></div>
<div class="third"></div>
</main>
<button>Add</button>
I would suggest you to go with position properties. Since you have a little difference between the order of your DOM element and their visual representation, like 1,2,3 in the DOM, but visually it's more like 1,3,2.
However, in such situation float is your enemy. I'm not 100% sure about flex, AFAIK flex would keep all the elements inside the parent element and prevent the scrolling.
If you go with absolute positioning, (since you already have the heights and widths defined)
Apply:
position: relative to the main element, it will be the base point of the child elements if they are set to absolute.
overflow-x: scroll to the main element. it will allow you to scroll horizontally when you increase the width of your second element.
position: absolute on .first, .second, .third, as you have the height and width defined, now set their position accordingly, check the snippet, you'll get it.
Finally you're good to add more value to your width of the target element.
Tip: always keep a consistency in your css units, for example, if used vh / vw use this for similar elements at least, or if px / em / rem is used, try to use the same accordingly.
Check the snippet in full page mode
let counter = 0;
document.querySelector("button").addEventListener("click", function() {
document.querySelector(".second").style.width = `calc(50vw + ${counter}vw)`;
document.querySelector("#added").textContent = counter;
counter++;
});
* {
padding: 0;
margin: 0;
}
main {
overflow-x: scroll;
position: relative;
min-height: 80vh;
}
.first,
.third {
height: 40vh;
width: 50vw;
background-color: black;
position: absolute;
left: 0;
top: 0;
}
.third {
background-color: red;
top: 40vh;
}
.second {
height: 80vh;
width: 50vw;
background-color: blue;
position: absolute;
left: 50vw;
top: 0;
}
button {
margin: 30px 5px;
border: 1px solid #cecece;
padding: 5px 10px;
}
<main>
<div class="first"></div>
<div class="second"></div>
<div class="third"></div>
</main>
<button>Add</button>
<p><span id="added">0</span>vw Added to blue div's width</p>

Resize child div element to fit in parent div on window resize

I have a div element (shown with red border in the image below), which I want to be able to fit in its parent div when the window is resized and not fall into the next line (the parent is the one with the green border).
I want the red div to have a starting width: 949px (in my current screen) in order to fit the entire space available as shown in the image, but be resizable, so that it doesn't fall into the next line if width: 949px is to much to fit.
In essence, I want it at all costs to cover the area it covers in the image even if in a narrower screen that means it will be like 10px wide.
How can I achieve this? Any solution using CSS, JavaScript or jQuery will be gladly accepted.
The image:
CSS:
#parent {
text-align: center;
width: 90%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: inline-block;
}
#child1-row2 {
text-align: left;
vertical-align: middle;
width: 288px;
display: inline-block;
}
#child2-row2 {
text-align: left;
vertical-align: middle;
width: 288px;
position: relative;
margin: 0 25px 0 25px;
display: inline-block;
}
#child3-row2 {/* The one with the red border */
vertical-align: middle;
height: 452px;
width: 949px;
overflow: hidden;
position: relative;
display: inline-block;
}
You can use flexbox to do this by using the flex-grow property.
HTML :
<div id="main">
<div id="box1">1</div>
<div id="box2">2</div>
<div id="box3">3</div>
</div>
CSS :
#main {
display: flex;
flex-flow: row;
width:100%;
min-height:50px;
}
#box1{
background-color:red;
width:100px;
}
#box2{
background-color:blue;
width:100px;
}
#box3{
background-color:green;
flex-grow: 1;
}
Here is a working JSFiddle
You can use css calc function for this. Support for calc seems to be quite good now.
As you have mentioned, the left side divs are of fixed width, say 120px each. Also suppose the margin between them is 30px. So, the total width left for your red div is 100% - (2*120 + 2*30)px i.e. (100% - 300px ).
#red-div
{
width: calc(100% - 300px);
}
Add % width or you can do following :
$(window).resize(function() {
var window_width = $(window).width();
var w1_width = $('.div1').width(); // The first element width
var w2_width = $('.div2').width(); // The second element width
var main_div_width = window_width - (w1_width+w2_width+gutter[i.e margin between all 3 elements]);
$('.main_div_width').css('width', main_div_width);
});

One "fixed" <div>-Tag (Footer) resize height of another

I want to show a webpage only on 100 percent. If the browser height changes I would seen the hole page. At the end of the page is a fixed footer with three different sizes (changeable by JS). If the footer expand the content should shrink.
HTML:
<div id="page">
<section id="content">
<div id="flexContent">
<div id="topFixedContent">
Content on top of the two flexible divs.
</div>
<div id="sizedContent">
This content have a fixed size. If ts too big scrollbars should be visible.
</div>
</div>
<div id="fixedFooter">
Footer with 3 different sizes inside content: 20px, 200px, 100%.
</div>
</section>
</div>
CSS:
body {
height: 100%;
}
#page {
height:100%;
width: 500px;
border-left: 2px solid grey;
border-right: 2px solid grey;
margin: auto;
}
#content {
height:100%;
width: 100%;
background-color:blue;
}
#flexContent {
heigth: 100%;
background-color:red;
overflow: hidden;
}
#topFixedContent {
height:20px;
background-color:yellow;
}
#sizedContent {
height:500px;
background-color:green;
border-bottom: 2px solid red;
}
#fixedFooter {
heigth: 20px;
width: 100%;
bottom: 0;
position: fixed;
background-color:orange;
}
JS (Jquery):
var counter = 0;
$( "#fixedFooter").click(function(){
if (counter == 0){
$("#fixedFooter").animate({height: "200px"});
counter++;
}
else if (counter == 1){
$("#fixedFooter").animate({height: "100%"});
counter++;
}
else if (counter == 2){
$("#fixedFooter").animate({height: "20px"});
counter = 0;
}
});
My example code on Fiddle: https://jsfiddle.net/mnrp72ho/7/
Inside my example are different problems:
fixedFooter schould have the same (variable) width of #page
flexContent should have ScrollBars (vertical & horizontal) if the 100% of hight are full
flexContent have to be visible if the footer have 20px or 200px
if it's possible too, #topFixed Content should be visible if fixedFooter have 100%
I have try a lot, but i haven't found a solution for me. Maybe flex is the right way i don't know. I am open for any solution, but topFixedContent and sizedContent hav to be together.
Notice: I work with JQuery and Bootstrap.
OK, I have solved my problem via JavaScript. My solution calculates the sized and after resize it reorder the div containers.
var counter = 0;
var resizeTimer;
window.onload = function(event) {
rescaleContent();
};
window.onresize = function(event) {
//Um die Anzahl der Funktions-Aufrufe zu verringern.
if (resizeTimer) {
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(function() {
resizeTimer = null;
rescaleContent();
}, 200);
};
function rescaleContent() {
console.log("resize");
footerHeight = $("#fixedFooter").height();
var scrollHeigth = 10;
var newHeight = $(window).height() - footerHeight - $('#topFixedContent').height() - scrollHeigth;
$("#flexContent").animate({height: newHeight});
$("#sizedContent").animate({height: newHeight});
$("#fixedFooter").animate({width: $("#page").width()});
}
$( "#fixedFooter").click(function(){
if (counter == 0){
$("#fixedFooter").animate({height: "200px"}).promise().then(function(){rescaleContent();});
counter++;
}
else if (counter == 1){
$("#fixedFooter").animate({height: "95%"}).promise().then(function(){rescaleContent();});
counter++;
}
else if (counter == 2){
$("#fixedFooter").animate({height: "20px"}).promise().then(function(){rescaleContent();});
counter = 0;
}
});
The CSS looks like (thank's to Stages):
html, body {
height: 100%;
overflow: hidden;
}
#page {
position: relative;
margin:0px auto;
height: auto !important;
min-height:100%;
height:100%;
width: 500px;
border-left: 2px solid grey;
border-right: 2px solid grey;
}
#content {
width: 100%;
height:100%;
background-color:blue;
}
#flexContent {
background-color:red;
}
#topFixedContent {
height:20px;
background-color:yellow;
}
#sizedContent {
width: 100%;
background-color:green;
border-bottom: 2px solid red;
overflow: auto;
z-index: 5;
}
#fixedFooter {
heigth: 20px;
bottom: 0;
position: fixed;
background-color:orange;
z-index: 1;
}
So I don't understand very well what you want but I can solve some of your problems.
1. fixedFooter schould have the same (variable) width of #page:
In the Css : #fixedFooter {width: 500px;}
2. flexContent should have ScrollBars (vertical & horizontal) if the 100% of hight are full:
In Css : #flexContent {overflow: auto;}
3. flexContent have to be visible if the footer have 20px or 200px:
Here you have several solutions, put in Css a z-index higher than the footer, you can ajust the sizedepending on the footer size like you did in JS.
4.if it's possible too, #topFixed Content should be visible if fixedFooter have 100%:
Dont go with a footer of 100% then.
If I missunterstood somethings tell me pls I can correct it.
Hope it helps.

How to make div take all the height available?

I have this HTML:
<div>
<span></span>
<textarea></textarea>
</div>
The Span can take up one or more lines (depends on the text it has and size of the Div). I want the Textarea to take all of the height left in div.
Please no jQuery.
https://jsfiddle.net/ntme8Lt4/
The CSS/style tag for that would just be max-height:100%; and width:100%;
This would hold the div's size constant if it is set to a percentage of its parent container or a constant value like 900px.
Since the size of span is not known, just leave it unspecified so it auto-sizes to content.
There's a circular issue here - the height of the div is (normally) determined by the size of its components. You need something to break the circle and determine the height of either the div or the text area.
You can use offsetHeight to get the heights of the different elements, and from there it is just a calculation of the container - span element to find the remaining.
document.querySelector('textarea').style.height = (document.querySelector('div').offsetHeight-document.querySelector('span').offsetHeight)+'px'
http://jsfiddle.net/rhbritton/4eck8dua/1/
If you're just wanting to use pure CSS and without the needs of tables etc you could try this approach.
HTML:
<div>
<span>
Hello<br>
Hello<br>
Hello
</span>
<textarea></textarea>
</div>
CSS:
div {
width: 400px;
height: 300px;
overflow: hidden;
border: 1px solid red;
}
span {
width: 100%;
display: block;
background-color: red;
}
textarea {
width: 100%;
height: 100%;
background-color: blue;
}
JSFiddle
Let me know if this works for you.
You can use clientWidth and clientHeight if your willing to use pure JS:
Here is the fiddle
function test()
{
var div = document.getElementById("testDiv");
var span = document.getElementById("testSpan");
var textArea = document.getElementById("testTextArea");
var height = div.clientHeight - span.clientHeight;
textArea.style.height = (height - 5) + "px";
textArea.style.width = (div.clientWidth - 5) + "px";
}
test();
Reference
you can use flex
div
{
display: flex;
flex-direction: column; /*layout top to bottom*/
height: 300px;
width: 400px;
border: 1px solid red;
}
span
{
display: block;
background-color: red;
}
textarea
{
background-color: blue;
height: 100%;
width: 100%;
flex-grow: 1; /*take up remaining space in flex container*/
}
}
https://jsfiddle.net/ntme8Lt4/13/
Thanks to the "possible duplicate" I came up with this solution:
<div>
<span>Hello<br>World</span>
<b><textarea></textarea></b>
</div>
div
{
height: 300px;
width: 400px;
border: 1px solid red;
display: table;
}
span
{
display: block;
background-color: red;
}
b
{
height: 100%;
width: 100%;
display: table-row;
}
textarea
{
height: 100%;
width: 100%;
background-color: blue;
}
https://jsfiddle.net/c42go079/

Javascript - move elements by pressing another element

Lets say I have a div with images, however not all have space to be displayed at same the time, so I used CSS property white-space: nowrap and overflow: hidden, so elements don't break into new lines or expand over div.
Now I need JavaScript technique that will allow me to move them left or right so user can reach these not visible images aswell. Think of it as a slider.
It should have two navigation buttons, left and right, by pressing each, images move in specific direction. Movement should be animated (not moving instantly, instead, they should move over specific period, frame by frame)
Here is jsfiddle demo: http://jsfiddle.net/rfLffev7/
(red and green div represent a button that should trigger functions)
HTML:
<div id="container">
<div id="left"></div>
<div id="track">
<img src="">
<img src="">
<img src="">
<img src="">
<img src="">
<img src="">
<img src="">
<img src="">
</div>
<div id="right"></div>
</div>
CSS:
#container {
width: 600px;
height: 200px;
margin: 10px auto;
}
#left {
width: 50px;
height: 200px;
float: left;
background: #500;
}
#track {
width: 500px;
height: 200px;
float: left;
background: #333;
white-space: nowrap;
overflow: hidden;
}
#track img {
width: 100px;
height: 100px;
border: 1px solid #fff;
margin-top: 50px;
margin-left: 10px;
}
#right {
width: 50px;
height: 200px;
float: left;
background: #050;
}
I would use absolute positioning for that as the CSS will be simpler. For the JavaScript, it's quite simple.
Here, I subtract 116px from the "margin-left" to move #track to the left and add 116px to #track to move it back to the right. I have not added any "stops" at either end, so in theory you could keep scrolling indefinitely.
document.getElementById("left").onclick = function(){
var currentPlace = parseInt(document.getElementById("track").style.marginLeft) || 0;
document.getElementById("track").style.marginLeft = (currentPlace - 116) + "px"
}
document.getElementById("right").onclick = function(){
var currentPlace = parseInt(document.getElementById("track").style.marginLeft) || 0;
document.getElementById("track").style.marginLeft = (currentPlace + 116) + "px"
}
Here's a working example (using absolute positioning): http://jsfiddle.net/rfLffev7/1/
I also added an additional :nth-child(even) class to make it more obvious that the images are moving:
#track img:nth-child(even) {
border: 1px solid #f00;
}
You can move the inner track using margins. For example, check the element for its margin value, then for the size of the image (or whatever distance you want to move the track), then add those two values together, then apply the new value to the track.
$('#right').click(function(){
var moveDistance = $('#track').find('img').width()
var moved = $('#track').css('marginLeft');
var moveIt = moveDistance - parseInt(moved)
$('#track').css('marginLeft', -moveIt);
});
I have updated your example with what I mean. The green button is rigged to move the distance of 1 image + the previous value of the element margin.
http://jsfiddle.net/rfLffev7/4/
You'll also need to make a few changes to your css to keep the other elements positions.
#container {
width: 600px;
height: 200px;
margin: 10px auto;
overflow:hidden;
position:relative;
}
#left {
width: 50px;
height: 200px;
left:0;
background: #500;
position:absolute;
z-index:1;
}
#track {
width: auto;
height: 200px;
float: left;
background: #333;
white-space: nowrap;
overflow: hidden;
position:absolute;
left:50px;
}
#track img {
width: 100px;
height: 100px;
border: 1px solid #fff;
margin-top: 50px;
margin-left: 10px;
}
#track img:nth-child(even) {
border: 1px solid #f00;
}
#right {
width: 50px;
height: 200px;
background: #050;
position:absolute;
right:0;
}

Categories

Resources