I've to make a single section with a vertical scroll transition effect please have a look at the video here for reference: https://drive.google.com/file/d/1Fy4BDqc0-LDrPnEVYuQZdiJ0Pk9qDXA5/view?usp=sharing
How could I achieve this design using javascript or if possible which widget would help me to design this on a wordpress website using elementor?
You can do it easily using pure JS and the Intersection Observer API - when a specific element scrolls into view, animate horizontally using CSS transition transform and translateX the inner element of the right sticky frame
const expo = function(el, entries) {
entries.forEach(entry => {
if (entry.isIntersecting)
el.style.transform = `translateX(-${100 * entry.target.dataset.expo}%)`;
});
};
document.querySelectorAll(".expo").forEach(el => {
const els = el.querySelector(".expo-slides");
const Obs = new IntersectionObserver(expo.bind(null, els), {threshold: 0.5});
el.querySelectorAll(".expo-article").forEach(el => Obs.observe(el));
});
/*QuickReset*/*{margin:0;box-sizing: border-box;}
body {font: 14px/1.4 sans-serif;}
header, footer {background: #ddd;padding: 60px 0;}
/* EXPO */
.expo {
position: relative;
display: flex;
}
.expo-articles {
flex: 1;
}
.expo-article {
min-height: 100vh;
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
box-shadow: inset 0 0 0 1px #000;
}
.expo-slidesWrapper {
flex: 1;
position: sticky;
top: 0px;
height: 100vh;
overflow: hidden;
}
.expo-slides {
position: relatie;
display: flex;
height: inherit;
flex-flow: row nowrap;
transition: 0.8s;
}
.expo-slide {
flex: 0 0 100%;
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
}
<header>
<h1>HEADER</h1>
</header>
<div class="expo">
<section class="expo-articles">
<article data-expo="0" class="expo-article">
<h1>Article 1</h1>
<p>Lorem ipsum article 1</p>
</article>
<article data-expo="1" class="expo-article">
<h1>Article 2</h1>
<p>Lorem ipsum article 2</p>
</article>
<article data-expo="2" class="expo-article">
<h1>Article 3</h1>
<p>Lorem ipsum article 3</p>
</article>
</section>
<div class="expo-slidesWrapper">
<div class="expo-slides">
<div class="expo-slide" style="background: #0bf;">1</div>
<div class="expo-slide" style="background: #f0b;">2</div>
<div class="expo-slide" style="background: #bf0;">3</div>
</div>
</div>
</div>
<footer>
<h2>FOOTER</h2>
</footer>
Related
Is there any way to get a behaviour similar to this shown on drawing?
I mean of course manually we can specify grid-row: span x, but grid-row: span auto seems doesn't work. I need all grid items to be the same size, but when one item has to resize (due to text overflow) i need to set the grid-row: span 2, and when it's getting bigger - respectively higher number.
To acheive something like this I need to write .js or can it be done with css only?
Here is code sandbox
let items = document.querySelectorAll('.item')
items.forEach(item => {
if(item.scrollHeight>item.clientHeight){
let itemSpan = Math.round(item.scrollHeight/40) + 1 // (height = 30) + (gap = 10) 40 =>
item.style.cssText = `--n : ${itemSpan}`
}
})
.container {
width: 200px;
margin: 15vw auto;
}
.grid {
width: 100%;
background-color: chartreuse;
display: grid;
justify-items: center;
grid-template-columns: 1fr 1fr;
grid-auto-rows: 30px;
grid-auto-flow: row;
grid-gap: 10px;
word-break: break-all;
}
.item {
background-color: gold;
min-height: 30px;
width: 50px;
padding: 5px;
grid-row: auto / span var(--n); /* var(--n) is calculated with js */
box-sizing: border-box;
}
<div class="container">
<div class="grid">
<div class="item">1</div>
<div class="item ">2 Lorem ipsum dolor sit amet consectetur adipisicing </div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5 t amet consectetur adipisi</div>
<div class="item">6 lorem</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9 t amet consectetur adipisi </div>
</div>
</div>
Sometimes good to review the fundamentals:
HTML is for structure.
CSS is for presentation.
JavaScript is for behavior.
Your problem falls within 3 ("item has to resize (due to text overflow)")
You can add min-height to ".item" class to set same size of grid items.
.item{
min-height:100px;
}
.App {
font-family: sans-serif;
text-align: center;
}
.container {
width: 200px;
height: 200px;
}
.grid {
width: 100%;
background-color: chartreuse;
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
grid-auto-flow: dense;
}
.item {
background-color: brown;
height: 30px;
min-height:100px;
}
.large {
height: fit-content;
word-break: break-all;
grid-row: span auto;
}
<div class="App">
<div class="container">
<div class="grid">
<div class="item"> </div>
<div class="item large">
asdasdasdasdasdsadasdasdasdasdasdasd{" "}
</div>
<div class="item"> </div>
<div class="item"> </div>
<div class="item"> </div>
<div class="item"> </div>
</div>
</div>
</div>
This question already has answers here:
How to disable equal height columns in Flexbox?
(4 answers)
Closed 1 year ago.
I have 2 divs both with the same class and when I add content to one the height of the other also changes.
function addContent() {
document.getElementsByClassName('list')[1].innerHTML += "<h1>test</h1>"
}
.container {
width: 79%;
margin: 0 auto;
}
.bansContainer {
display: flex;
margin: 25px 0;
overflow: auto;
justify-content: space-between;
}
.list {
background-color: #436935;
}
<div class="container">
<div class="bansContainer">
<div class="list">
<h1>
left
</h1>
</div>
<div>
<h1 class="list">
right
</h1>
<button onclick=addContent()>Click</button>
</div>
</div>
</div>
How can I change/update it in a way that only the height of the div with content being added changes?
function addContent() {
document.getElementsByClassName('list')[1].innerHTML += "<h1>test</h1>"
}
.container {
width: 79%;
margin: 0 auto;
}
.bansContainer {
display: flex;
margin: 25px 0;
overflow: auto;
justify-content: space-between;
}
.list {
background-color: #436935;
align-self: flex-start;
}
<div class="container">
<div class="bansContainer">
<div class="list">
<h1>
left
</h1>
</div>
<div>
<h1 class="list">
right
</h1>
<button onclick=addContent()>Click</button>
</div>
</div>
</div>
It is because you haven't specified height on the first column and it's continuing to adapt the height of its parent div aka bansContainer. So here are two approaches. One is you add align-self: flex-start; or you specify a height on the column.
function addContent() {
document.getElementsByClassName('list')[1].innerHTML += "<h1>test</h1>"
}
.container {
width: 79%;
margin: 0 auto;
}
.bansContainer {
display: flex;
margin: 25px 0;
overflow: auto;
justify-content: space-between;
}
.list {
background-color: #436935;
/*align-self: flex-start;*/
}
.n-h {
height: fit-content;
}
<div class="container">
<div class="bansContainer">
<div class="list n-h">
<h1>
left
</h1>
</div>
<div>
<h1 class="list">
right
</h1>
<button onclick=addContent()>Click</button>
</div>
</div>
</div>
I have a slider that has 4 articles on it. I can get it to slide each way by 1 article, but can't seem to get it to repeat the action on the second time of clicking the 'left' button. I'm not sure if it's the counter that is the problem or the transform value? I do need to use transform instead of left or right because I need it execute at 60fps on the animation.
Codepen: https://codepen.io/emilychews/pen/vYXJyqZ
var leftButton = document.getElementById("left-button"),
rightButton = document.getElementById("right-button"),
article = document.querySelectorAll(".article"),
counter = 0,
articleWidth = article.offsetWidth;
if (counter <=1) {
leftButton.addEventListener("click", function () {
article.forEach(function (item) {
item.style.transform = "translateX(-100%)";
item.style.transition = "all 2s";
counter += 1;
});
});
}
if (counter < article.length) {
rightButton.addEventListener("click", function () {
article.forEach(function (item) {
item.style.transform = "translateX(0)";
item.style.transition = "transform 2s";
counter -= 1;
});
});
}
* {
margin: 0;
box-sizing: border-box;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
.row {
width: 50%;
background: red;
overflow: hidden;
margin-bottom: 2rem;
}
.article-wrapper {
display: flex;
width: 160%;
}
.article {
width: 70%;
background: blue;
margin: 0 1rem;
padding: 4rem 1rem;
}
p {
color: white;
}
<div class="row">
<div class="article-wrapper">
<article class="article">
<p>Article 1</p>
</article>
<article class="article">
<p>Article 2</p>
</article>
<article class="article">
<p>Article 3</p>
</article>
<article class="article">
<p>Article 4</p>
</article>
</div>
</div>
<button id="left-button">Left</button>
<button id="right-button">Right</button>
One issue is that you only need to add the event listeners once and there's no need to condition adding event listeners off of the counter. If you use the counter approach, you can return early in the click handler when the desired criteria is met.
The next issue is that your "left" handler isn't working more than once because your transform has to be 100 * counter transformed. The following code keeps pretty close to your initial design but generally works.
var leftButton = document.getElementById("left-button"),
rightButton = document.getElementById("right-button"),
article = document.querySelectorAll(".article"),
counter = 0,
articleWidth = article.offsetWidth;
leftButton.addEventListener("click", function () {
if (counter === article.length) return;
counter += 1;
article.forEach(function (item) {
item.style.transform = `translateX(-${counter}00%)`;
item.style.transition = "all 2s";
});
});
rightButton.addEventListener("click", function () {
if (counter === 0) return;
counter -= 1;
article.forEach(function (item) {
item.style.transform = "translateX(0)";
item.style.transition = "transform 2s";
});
});
* {
margin: 0;
box-sizing: border-box;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
.row {
width: 50%;
background: red;
overflow: hidden;
margin-bottom: 2rem;
}
.article-wrapper {
display: flex;
width: 160%;
}
.article {
width: 70%;
background: blue;
margin: 0 1rem;
padding: 4rem 1rem;
}
p {
color: white;
}
<div class="row">
<div class="article-wrapper">
<article class="article">
<p>Article 1</p>
</article>
<article class="article">
<p>Article 2</p>
</article>
<article class="article">
<p>Article 3</p>
</article>
<article class="article">
<p>Article 4</p>
</article>
</div>
</div>
<button id="left-button">Left</button>
<button id="right-button">Right</button>
From my research in this problem, I've learned CSS grids appear to capable of quite complex behaviour. My scenario is simpler and I was expecting to have 4 evenly spaced panel boxes with code below. My question is why the horizontal gap is not centred in the middle vertically? I worked through trail&error to test various combinations of alignment, justification and grid specs but could not find a solution. What do I need to add to my code to have the gap centred vertically on the page?
.main-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 20px;
height: 100vh;
align-items: stretch;
margin: 0;
padding: 0;
justify-content: space-between;
}
.container {
border: 3px solid black;
display: flex;
position: relative;
flex-direction: column;
margin: 0;
padding: 0;
}
.shared {
justify-content: center;
border: none;
}
.sub-container {
border: 3px solid black;
align-items: stretch;
height: 100%;
margin: 0;
padding: 0;
}
<div class="main-container">
<div class="container" id="A">
<h1>Section A</h1>
<p id="A-values">A Values</p>
</div>
<div class="container" id="B">
<h1>Section B</h1>
<p id="B-values">B Values</p>
</div>
<div class="container" id="C">
<h1>Section C</h1>
<p id="C-values">C Values</p>
</div>
<div class="container shared" id="D">
<div class="sub-container">
<h2>SubSection D1</h2>
<p id="D1-values">D1 Values</p>
</div>
<div class="sub-container">
<h2>SubSection D2</h2>
<p id="D2-values">D2 Values</p>
</div>
<div class="sub-container">
<h2>SubSection D3</h2>
<p id="D3-values">D3 Values</p>
</div>
</div>
</div>
By default, the height is set to match the longest item on a row, the height on the bottom row is different to the top simply because there's more content in one of it's columns.
Try setting the rows as you have the columns, add grid-template-rows: repeat(2, 1fr); to the main-container class
I have this div with three inner divs.
ONE - I am div TWO - I am div THREE - I am div
But in mobile it can only fit two divs in a row horizontally, I need divs after 2nd to step down.
Like this:
ONE - I am div TWO - I am div
THREE - I am div
How do I do this?
I am using flex.
Edit
I have added HTML code.
I am using React and other UI component and I tried to minimize it in HTML. It's something like this right now.
<div class="parent">
<div class="child">
<span>ONE</span>
<p>I am div</p>
</div>
<div class="child">
<p>TWO</p>
<p>I am div</p>
</div>
<div class="child">
<span>THREE</span>
<p>I am div</p>
</div>
<div>
.parent {
display: flex;
justify-content: space-around;
margin-bottom: 3rem;
white-space: nowrap;
}
.child {
display: flex;
align-items: center;
margin-left: 1rem;
margin-right: 1rem;
}
You can use flex-wrap to continue on the next line. justify-content will center the div
.outer {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
/* Styles below are for demonstration purposes */
.inner {
height: 50px;
width: 300px;
}
.red {
background: red;
}
.green {
background: green;
}
.blue {
background: blue;
}
<div class="outer">
<div class="inner red">A</div>
<div class="inner green">B</div>
<div class="inner blue">C</div>
</div>
This will work for responsive layout, and it also permits them to fit in one line, if the screen size allows it. You can use media query to set it for mobile only.
.outer{
display: flex;
flex-flow: wrap;
text-align: center;
}
.inner{
flex-grow: 1;
}