Auto center horizontal scrollbar - javascript

I've found some related cases but no answer works for me. My page have a big horizontal image but I need to start scrolling it from the middle (just horizontally), always and in any resolution.
var body = document.body; // For Safari
var html = document.documentElement; // Chrome, Firefox, IE and Opera
body.scrollLeft = (html.clientWidth - body.scrollWidth) / 2
html.scrollLeft = (html.clientWidth - body.scrollWidth) / 2
body {
background-color: 0178fa;
padding: 0;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
overflow: auto;
}
#page {
width: 100%;
height: 100%;
margin: 0 auto;
padding: 0;
display: block;
}
#wrap-landing {
position: relative;
margin: 0 auto;
padding: 0;
content: url(https://i.imgur.com/gb6EyHk.png);
width: 1920px;
height: 1080px;
}
<div id="page">
<div id="wrap-landing"></div>
</div>

You could use standard javascript: window.scroll(x, y).
Ex:
window.addEventListener('load', function() {
setTimeout(function() {
window.scroll(x, y);
},1)
})
x-coord is the pixel along the horizontal axis of the document that you want displayed in the upper left.
y-coord is the pixel along the vertical axis of the document that you want displayed in the upper left.
window.addEventListener('load', function() {
setTimeout(function() {
window.scroll(screen.width/2, 0);
},1)
})
body{
background-color:0178fa;
padding:0;
text-align:center;
display: flex;
justify-content: center;
align-items: center;
overflow:auto;
}
#page {
width:100%;
height:100%;
margin:0 auto;
padding:0;
display:block;
}
#wrap-landing{
position:relative;
margin:0 auto;
padding:0;
content:url(https://i.imgur.com/gb6EyHk.png);
width:1920px;
height:1080px;
}
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="page">
<div id="wrap-landing">
</div>
</div>
</body>
</html>

The math would be:
centerX = (el.scrollWidth - el.clientWidth) / 2
Example on a scrollable #page Element:
const el = (sel, par) => (par || document).querySelector(sel);
const elPage = el("#page");
const centerX = (elPage.scrollWidth - elPage.clientWidth) / 2;
const centerY = (elPage.scrollHeight - elPage.clientHeight) / 2;
elPage.scrollTo(centerX, centerY);
#page {
display: flex;
overflow: scroll;
height: 200px;
}
#image {
flex: 0 0 auto;
margin: auto;
content: url(https://i.imgur.com/gb6EyHk.png);
width: 1920px;
height: 1080px;
}
/*
PS: flex and margin:auto is used to center
#image in case is smaller than the parent.
*/
<div id="page">
<div id="image"></div>
</div>

Related

overflow-anchor doesn't work for horizontal scrolling

I would like to build an infinite horizontal scroll that scrolls in both directions - left and right. As user scrolls to the left, new content is prepended to the scrollable element (think scrolling through a schedule history, for example). As they scroll to the right, content is appended.
I have learned that browsers anchor content when scrolling up and down which is fantastic, exactly what I'd expect. The effect of that is that prepending content to the scrolled element anchors user to their current, logical position and the content doesn't "jump".
But the anchoring doesn't seem to work when scrolling left or right. The behaviour is as if I set overflow-anchor: none. What can I do to make it work as well as when scrolling up?
let topCounter = 0;
document.querySelector('.scrollable-top').scrollTo({ top: 100 });
document.querySelector('.scrollable-top').onscroll = (event) => {
if (event.target.scrollTop < 100) {
let box = document.createElement('div');
box.className = 'content-box';
box.textContent = `${topCounter--}`;
document.querySelector('.scrollable-top').prepend(box);
}
};
let leftCounter = 0;
document.querySelector('.scrollable-left').scrollTo({ left: 100 });
document.querySelector('.scrollable-left').onscroll = (event) => {
if (event.target.scrollLeft < 100) {
let box = document.createElement('div');
box.className = 'content-box';
box.textContent = `${leftCounter--}`;
document.querySelector('.scrollable-left').prepend(box);
}
};
.scrollable-top {
width: 200px;
height: 250px;
overflow-y: auto;
border: solid 1px black;
}
.scrollable-left {
display: flex;
width: 250px;
overflow-x: auto;
border: solid 1px black;
}
.content-box {
flex: 1 0 auto;
height: 150px;
width: 150px;
border: solid 1px red;
display: flex;
justify-content: center;
align-items: center;
}
<div class="scrollable-top">
<div class="content-box">1</div>
<div class="content-box">2</div>
<div class="content-box">3</div>
</div>
<div class="scrollable-left">
<div class="content-box">1</div>
<div class="content-box">2</div>
<div class="content-box">3</div>
</div>
Scroll the horizontal container to the right by 150 using scrollBy(150, 0):
let topCounter = 0;
document.querySelector('.scrollable-top').scrollTo({ top: 100 });
document.querySelector('.scrollable-top').onscroll = (event) => {
if (event.target.scrollTop < 100) {
let box = document.createElement('div');
box.className = 'content-box';
box.textContent = `${topCounter--}`;
document.querySelector('.scrollable-top').prepend(box);
}
};
let leftCounter = 0;
document.querySelector('.scrollable-left').scrollTo({ left: 100 });
document.querySelector('.scrollable-left').onscroll = (event) => {
if (event.target.scrollLeft < 100) {
let box = document.createElement('div');
box.className = 'content-box';
box.textContent = `${leftCounter--}`;
document.querySelector('.scrollable-left').prepend(box);
// solution ------------------
event.target.scrollBy(150, 0);
}
};
.scrollable-top {
width: 200px;
height: 250px;
overflow-y: auto;
border: solid 1px black;
display: inline-block;
float:left;
}
.scrollable-left {
display: flex;
width: 250px;
overflow-x: auto;
border: solid 1px black;
float:right;
}
.content-box {
flex: 1 0 auto;
height: 150px;
width: 150px;
border: solid 1px red;
display: flex;
justify-content: center;
align-items: center;
}
<div class="scrollable-top">
<div class="content-box">1</div>
<div class="content-box">2</div>
<div class="content-box">3</div>
</div>
<div class="scrollable-left">
<div class="content-box">1</div>
<div class="content-box">2</div>
<div class="content-box">3</div>
</div>
As per the specs, following is the intent behind such anchoring:
Changes in DOM elements above the visible region of a scrolling box can result in the page moving while the user is in the middle of consuming the content.
This spec proposes a mechanism to mitigate this jarring user experience
by keeping track of the position of an anchor node and adjusting the scroll offset accordingly.
This spec also proposes an API for web developers to opt-out of this behavior.
Since no page loads horizontally, I think they didn't implement this for horizontal scrollbars. Also, apart from above use case it makes no sense to implement this behavior.
Note: Safari doesn't implement the overflow-anchor behavior. So, your code for vertical scroll fails in Safari.
I've tried my code, for horizontal scrolling, on Safari and it works. So incase you want to implement infinite vertical scroll, and want to support all the browsers, then you'll have to optout of overflow-anchor behavior and use scrollBy(x,y) to do it manually. :(
I tried to fix your code and got this option
let leftCounter = -2;
let rightCounter = 2;
document.querySelector('.scrollable-left').scrollTo({ left: 100 });
document.querySelector('.scrollable-left').onscroll = (event) => {
if (event.target.scrollLeft < 100) {
let box = document.createElement('div');
box.className = 'content-box';
box.textContent = `${leftCounter--}`;
document.querySelector('.scrollable-left').prepend(box);
event.target.scrollLeft += 250
}
if ((event.target.scrollWidth - event.target.scrollLeft - 250) < 100) {
let box = document.createElement('div');
box.className = 'content-box';
box.textContent = `${rightCounter++}`;
document.querySelector('.scrollable-left').append(box);
}
};
.scrollable-top {
width: 200px;
height: 250px;
overflow-y: auto;
border: solid 1px black;
}
.scrollable-left {
display: flex;
width: 250px;
overflow-x: auto;
border: solid 1px black;
}
.content-box {
flex: 1 0 auto;
height: 150px;
width: 150px;
border: solid 1px red;
display: flex;
justify-content: center;
align-items: center;
}
<div class="scrollable-left">
<div class="content-box">-1</div>
<div class="content-box">0</div>
<div class="content-box">1</div>
</div>

How do I change the left margin of div based on scroll and using javascript?

I am new to Javascript and CSS. I have a div that will contain an image. The below code, I pieced it together after watching some YouTube videos and going over some documentation, however I am sure that this is not the right code.
https://jsfiddle.net/0hp97a6k/
* {
margin: 0;
padding: 0;
}
body {
background-color: powderblue;
height: 2000px;
padding: 0 0;
}
div {
margin: 0;
}
.headerspace {
width: 100%;
height: 20px;
background-color: white;
}
.header {
width: 100%;
height: 300px;
background-color: maroon;
display: flex;
}
.logo {
width: 200px;
height: 200px;
background-color: red;
margin-top: 50px;
margin-left: 50px;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="headerspace"></div>
<div class="header">
<div class="logo" id="logoid">
</div>
</div>
<script type="text/javascript">
let logo = document.getElementById("logoid");
window.addEventListener('scroll', function() {
var value = window.scrollY;
logo.style.marginleft = value * 0.5 + 'px';
})
</script>
</body>
</html>
How do I set the left margin based on scroll?
Also can scroll based properties be applied to two margins, say top and right at the same time?
marginleft should be marginLeft in your javascript
<script type="text/javascript">
let logo = document.getElementById("logoid");
window.addEventListener('scroll', function(){
var value = window.scrollY;
logo.style.marginLeft = value * 0.5 + 'px';
})
</script>
And then if you want to edit the left and top you can do the following
<script type="text/javascript">
let logo = document.getElementById("logoid");
window.addEventListener('scroll', function(){
var value = window.scrollY;
logo.style.marginLeft = value * 0.5 + 'px';
logo.style.marginTop = value * 0.5 + 'px';
})
</script>
To make sure the logo element goes back where it started you should edit the css like this
* {
margin: 0;
padding: 0;
}
body {
background-color: powderblue;
height: 2000px;
padding: 0 0;
}
div{
margin: 0;
}
.headerspace{
width: 100%;
height: 20px;
background-color: white;
}
.header{
width: 100%;
height: 300px;
background-color: maroon;
display: flex;
padding-top: 50px;
padding-left: 50px;
}
.logo{
width: 200px;
height: 200px;
background-color: red;
}
I have removed the margin from .logo because that will be overwritten and added those values as padding to the parent (.header)

Calculating the area of a rectangle with different images

I am in the process of making a website for calculating the area of differing lego bricks and am unsure on how to do this. I have created 13ish images of lego bricks with assigned heights and widths.one has been copied below I understand how to do the multiplication and checking (response of user vs actual answer) aspect of this website but don't know how randomise these images and then store the variables for them such as length and width (to calculate the area). Would you be able to suggest any ideas on the javascript for this?
var number1;
var number2;
var response;
var calcanswer;
var score = 0;
window.onload = areaquestion;
var areas = new Array("Images/1*1.png","Images/2*1.png","Images/2*2.png","Images/3*1.png","Images/3*2.png","Images/4*1.png","Images/4*2.png","Images/4*3.png","Images/5*1.png","Images/5*2.png","Images/6*1.png","Images/6*2.png","Images/6*4.png");
function areaquestion() {
var randomNum = Math.floor(Math.random() * areas.length);
document.getElementById("question").src = areas[randomNum];
number1 = Math.floor( 1 + Math.random() * 9 );
number2 = Math.floor( 1 + Math.random() * 9 );
var question = document.getElementById("question");
question.innerHTML = "What is the area of this shape?";
calcanswer = (number1*number2);
}
function check()
{
var statusDiv = document.getElementById("status");
response=document.getElementById("answer").value;
if(response != calcanswer)
statusDiv.innerHTML="Incorrect";
else
if (response==calcanswer)
{
statusDiv.innerHTML="Very good!";
score ++;
document.getElementById("score").textContent = score
document.getElementById("answer").value = "";
problem();
}
}
* {
box-sizing: border-box;
}
/* Style the body */
body {
font-family: Arial;
margin: 0;
}
/* Header/logo Title */
.header {
padding: 30px;
text-align: center;
background: yellow;
color: black;
font-family: Arial, Helvetica, sans-serif;
}
.score {
display:flex;
flex-wrap: wrap;
float: right;
}
#answer {
width: 30%;
background-color: yellow;
color:black;
border-color: black;
padding: 12px 20px;
float: initial;
text-size-adjust: 30;
}
#solve {
width: 20%;
background-color: blue;
color:rgb(255, 255, 255);
border-color: black;
padding: 12px 20px;
font-size: 100%;
}
/* Column container */
.row {
display: flex;
flex-wrap: wrap;
}
/* Create two unequal columns that sits next to each other */
/* Sidebar/left column */
.side {
flex: 50%;
background-color: #ffffff;
padding: 20px;
color:#000;
}
/* Main column */
.main {
flex: 50%;
background-color: white;
padding: 20px;
}
/* Footer */
.footer {
display: flex;
flex-wrap: wrap;
padding: 100px;
text-align: right;
background: #fff;
flex-direction: column;
}
#practicebtn{
padding:30px;
}
#playbtn{
padding:30px;
}
/* Responsive layout - when the screen is less than 700px wide, make the two columns stack on top of each other instead of next to each other */
#media screen and (max-width: 700px) {
.row, .navbar, .footer {
flex-direction: column;
}
}
<!DOCTYPE html>
<html>
<title>Lego Area</title>
<head>
<link rel="stylesheet" href="CSS/Play.css">
<script src="JavaScript/Play.js"></script>
</head>
<body onload="problem();">
<div class="header">
<h1>LEGO AREA</h1>
<p>Calculating <b>area</b> with Emmet.</p>
<div id="score" class="score" value="SCORE:"></div>
</div>
<form>
<div class="row">
<div class="side">
<div id="question"></div>
<div id ="prompt"></div>
<input type="text" id="answer"/>
</div>
<div class="main">
<input id="solve" type="button" value="CHECK!" onclick="check()" />
</div>
</div>
</form>
<div id="status"></div>
<!-- Footer -->
<div class="footer">
<div class="practice"> <img src="Images/legoBlue2.png" id="practicebtn" width="20%"></div>
<div class="play"> <img src="Images/legored2.png" id="playbtn" width="20%"></div>
</div>
</body>
</html>
Could you create an array of objects containing all your legos with key/value pairs indicating the source image, the length, width, and area of each? Such as:
const legos = [
{
name: lego01
image: "image01.png",
len: 10,
wid: 4,
area: 40
},
{
name: lego02
image: "image02.png",
len: 6,
wid: 6,
area: 36
}
{
name: lego03
image: "image03.png",
len: 12,
wid: 8,
area: 96
}
]
Then you can have your program choose a random lego. And you can access it's area or length and width using the syntax randomLego.width.
I hope I understood what you were wanting to do.

How do i center two divs vertically in Javascript?

Here is the code snippet:
var wrapper = document.createElement('DIV');
wrapper.setAttribute("width", x * rows);
wrapper.setAttribute("height", y * columns);
wrapper.align = "center";
var buttonWrap = document.createElement('DIV');
buttonWrap.setAttribute("style", "clear:float");
As you can see in my code snippet, I have tried to center my div. But this code doesn't work. What works is making both divs fixed. But at the end of the day, the second div will then be upon the first div.
Please help.
If you can use only CSS I would do it this way:
.container {
width: 500px;
height: 150px;
border: solid black 1px;
/* Align center */
display: flex;
justify-content: center;
align-items: center;
}
.small {
background-color: red;
width: 100px;
height: 30px;
}
.big {
background-color: green;
width: 100px;
height: 100px;
}
<div class="container">
<div class="small"></div>
<div class="big"></div>
</div>
If you want to do it in javascript, apply the style written above in CSS this way:
var container = document.getElementsByClassName('container')[0];
container.style.display = "flex";
and so on...

How to reorder divs using flex box?

I am trying to keep a seo friendly and semantic structure for my DOM, without repeating whole elements to display them in various positions.
My layout is based on display: flex items. I try to achieve the following:
Important things to know:
I do not want to show/hide divs based on the window width (to avoid unnecessary duplicates)
None of the divs has a known or fixed height
On desktops the divs should be vertical centered, while the right column builds a tag-team (behaves like one single div)
The layout needs to support at least IE11+
Is there a css only solution to achieve this?
If not, it would be easy to cut out the green div and paste its content into the pink one using javascript. But I do have concerns about the performance and "flickering" using this, although resizing the browser makes it more complicated. Do I make this needlessly complicated?
Here is fiddle showing a working solution but with javascript:
CODEPEN DEMO
In general, you can't do this with Flexbox alone, though there might be a compromise based on each given case.
With Flexbox alone, using fixed height, you can accomplish this
* {
box-sizing: border-box;
}
body, html {
margin: 0;
}
.flex {
width: 90%;
margin: 5vh auto;
height: 90vh;
background: rgba(0, 0, 0, 0.05);
display: flex;
flex-flow: column wrap;
}
.flex div {
flex: 1;
width: 50%;
}
.flex div:nth-child(2) {
order: -1;
}
.flex::before {
content: '';
height: 100%;
}
#media (max-width:768px) {
.flex div {
width: auto;
}
.flex::before {
display: none;
}
.flex div:nth-child(2) {
order: 0;
}
}
/* styling */
.flex-child {
color: white;
font-size: 2em;
font-weight: bold;
}
.flex-child:nth-child(1) {
background: #e6007e;
}
.flex-child:nth-child(2) {
background: #f4997c;
}
.flex-child:nth-child(3) {
background: #86c06b;
}
<div class="flex">
<div class="flex-child">
<div>Top/Right</div>
</div>
<div class="flex-child">
<div>Center/Left</div>
</div>
<div class="flex-child">
<div>Bottom/Right</div>
</div>
</div>
In this case, where no fixed height is allowed, you can combine Flexbox and float.
By set up it for mobile using Flexbox where you add the center item first in the markup and then, with order, move it between the top and bottom.
With a media query you then simply make the flex container a block element and use float to position the left to the left and the right to the right.
* {
box-sizing: border-box;
}
body, html {
margin: 0;
}
.flex {
max-width: 1024px;
width: 90%;
margin: 5vh auto;
height: 90vh;
background: rgba(0, 0, 0, 0.05);
display: flex;
flex-direction: column;
}
.flex-child {
color: white;
font-size: 2em;
font-weight: bold;
padding: 5%;
flex-basis: 33.333%;
display: flex;
align-items: center;
}
.flex-child:nth-child(1) {
background: #e6007e;
order: 1;
}
.flex-child:nth-child(2) {
background: #f4997c;
}
.flex-child:nth-child(3) {
background: #86c06b;
order: 2;
}
#media (min-width: 768px) {
.flex {
display: block;
}
.flex-child {
width: 50%;
}
.flex-child:nth-child(1) {
float: left;
height: 100%;
}
.flex-child:nth-child(2),
.flex-child:nth-child(3) {
float: right;
height: 50%;
}
}
<div class="flex">
<div class="flex-child">
<div>Center/Left</div>
</div>
<div class="flex-child">
<div>Top/Right</div>
</div>
<div class="flex-child">
<div>Bottom/Right</div>
</div>
</div>
Update
Here is another version combining Flexbox with position: absolute, which also vertically center the items in desktop mode
Updated, added a script to control so the absolute positioned element won't get bigger than the right items, and if so, adjust the flex containers height.
Note, the script is by no means optimized, it is only there to show how a fix in certain situations
(function() {
window.addEventListener("resize", resizeThrottler, false);
var fp = document.querySelector('.flex');
var fi = fp.querySelector('.flex-child:nth-child(1)');
var resizeTimeout;
function resizeThrottler() {
// ignore resize events as long as an actualResizeHandler execution is in the queue
if ( !resizeTimeout ) {
resizeTimeout = setTimeout(function() {
resizeTimeout = null;
actualResizeHandler();
// The actualResizeHandler will execute at a rate of 15fps
}, 66);
}
}
function actualResizeHandler() {
// handle the resize event
if (fp.offsetHeight <= fi.offsetHeight) {
fp.style.cssText = 'height: '+fi.offsetHeight+'px';
} else {
fp.style.cssText = 'height: auto';
}
}
window.addEventListener('load', function() {
actualResizeHandler();
})
}());
* {
box-sizing: border-box;
}
body, html {
margin: 0;
}
.flex {
position: relative;
max-width: 1024px;
width: 90%;
margin: 5vh auto;
height: 90vh;
background: rgba(0, 0, 0, 0.05);
display: flex;
flex-direction: column;
}
.flex-child {
color: white;
font-size: 2em;
font-weight: bold;
padding: 5%;
}
.flex-child:nth-child(1) {
order: 1;
}
.flex-child:nth-child(3) {
order: 2;
}
.flex-child:nth-child(1) div {
background: #e6007e;
}
.flex-child:nth-child(2) div {
background: #f4997c;
}
.flex-child:nth-child(3) div {
background: #86c06b;
}
#media (min-width: 768px) {
.flex {
justify-content: center;
}
.flex-child {
width: 50%;
}
.flex-child:nth-child(1) {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.flex-child:nth-child(n+2) {
margin-left: 50%;
}
}
<div class="flex">
<div class="flex-child">
<div>Center/Left<br>with more<br>content<br>than any<br>of the<br>other items<br>other items<br>other items<br>other items<br>other items</div>
</div>
<div class="flex-child">
<div>Top/Right<br>with more<br>content</div>
</div>
<div class="flex-child">
<div>Bottom/Right<br>with more</div>
</div>
</div>
With script one can also reorder/move items between elements.
Stack snippet
You can also combine this with a media query, and use it to do the actual re-order of the elements
$( document ).ready(function() {
$(window).resize(function() {
if ($( window ).width() < 600 ) {
$(".one").insertBefore("#b");
} else {
$(".one").insertBefore(".two");
}
});
});
.outer, #flex, #flex2 {
display: flex;
flex-direction: column;
}
#a {
order: 4;
background: #ccc;
}
#b {
order: 1;
background: #aaa;
}
#c {
order: 3;
background: #d33;
}
.one {
order: 2;
background: #aaa;
}
.two {
order: 5;
background: #aaa;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outer">
<div id="flex">
<div id="a">A</div>
<div id="b">B</div>
<div id="c">C</div>
</div>
<div id="flex2">
<div class="one">Show me 2nd</div>
<div class="two">Show me 5th</div>
</div>
</div>
Update 2 (answered at another question but later moved here)
If we talk about smaller items, like a header or smaller menus, one can do what many website platform providers like "squarespace", "weebly", "wordpress", etc does. Their templates holds different markup structures, where an item sometimes exist twice, one visible for desktop, another for mobile.
Also, being so small, there will be less to nothing when it comes to performance (and personally I don't see anymore issue with this than having duplicate CSS rules, one for each screen size, and happily do this instead of introducing script).
Fiddle demo
Stack snippet
.container {
display: flex;
}
.container > div {
width: 50%;
}
.container div:nth-child(-n+2) {
border: dashed;
padding: 10px;
}
.container > div:nth-child(1) {
display: none; /* hide outer "Flower" */
}
#media (max-width:768px) {
.container {
flex-direction: column;
}
.container div {
width: auto;
}
.container div:nth-child(1) {
display: block; /* show outer "Flower" */
}
.container div:nth-child(3) div:nth-child(1) {
display: none; /* hide inner "Flower" */
}
}
<div class="container">
<div>Flower</div>
<div>Tree</div>
<div>
<div>Flower</div>
<div>Bee</div>
</div>
</div>

Categories