HTML - Resize multiple divs and their content - html

I am looking to create a bottom pannel with a resizable height. The top pannel consists of 2 divs with a resizable width. I was able to follow this https://htmldom.dev/create-resizable-split-views/ , but the vertical resizing is not resizing the contents of the two top divs. How can I fill the contents of the top container with the contents of the two Divs, to ensure that they resize when the bottom pannel is dragged up?
In other words, I'm looking for two top horizontally resizable pannels and one bottom pannel vertically resizable from them, while shrinking/expanding the contents during resize.
Edit: The bottom container needs to be set on all tabs and show up under all tab content on the page.
<div class="container">
<div class = "container__top">
<div class="tab-content" >
<body class="noscroll">
<div class="Tab1">
<div class="main-body">
<div class="page-wrapper">
<div class="row">
<div class="col-sm-12">
<div class="container__left">
STUFF</div>
<div class="resizer" data-direction="horizontal"></div>
<div class="container__right">
STUFF</div>
</div>
</div>
</div>
</div>
<div class="Tab2"></div>
</body>
</div>
</div>
<div class="resizer" data-direction="vertical"></div>
<div class = "container__bottom">
STUFF</div>

You could try something like this. You'll have to be explicit for a few things, like parent height and the min/max heights for top and bottom sections, but this could be a decent start. It's ugly, sorry.
edit: it's still ugly, and you'll have to fix up the tab/hide function for more tabs, but this works as intended as far as I can tell.
document.addEventListener('DOMContentLoaded', function() {
const resizable = function(resizer) {
const direction = resizer.getAttribute('data-direction') || 'horizontal';
const prevSibling = resizer.previousElementSibling;
const nextSibling = resizer.nextElementSibling;
// The current position of mouse
let x = 0;
let y = 0;
let prevSiblingHeight = 0;
let prevSiblingWidth = 0;
// Handle the mousedown event
// that's triggered when user drags the resizer
const mouseDownHandler = function(e) {
// Get the current mouse position
x = e.clientX;
y = e.clientY;
const rect = prevSibling.getBoundingClientRect();
prevSiblingHeight = rect.height;
// Attach the listeners to `document`
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
};
const mouseMoveHandler = function(e) {
// How far the mouse has been moved
const dx = e.clientX - x;
const dy = e.clientY - y;
const parentHeight = resizer.parentNode.getBoundingClientRect().height;
const h = (prevSiblingHeight + dy)
prevSibling.style.height = `${h}px`;
nextSibling.style.height = `${parentHeight - h}px`;
const cursor = 'row-resize';
resizer.style.cursor = cursor;
document.body.style.cursor = cursor;
prevSibling.style.userSelect = 'none';
prevSibling.style.pointerEvents = 'none';
nextSibling.style.userSelect = 'none';
nextSibling.style.pointerEvents = 'none';
};
const mouseUpHandler = function() {
resizer.style.removeProperty('cursor');
document.body.style.removeProperty('cursor');
prevSibling.style.removeProperty('user-select');
prevSibling.style.removeProperty('pointer-events');
nextSibling.style.removeProperty('user-select');
nextSibling.style.removeProperty('pointer-events');
// Remove the handlers of `mousemove` and `mouseup`
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
};
// Attach the handler
resizer.addEventListener('mousedown', mouseDownHandler);
};
// Query all resizers
document.querySelectorAll('.resizer').forEach(function(ele) {
resizable(ele);
});
// Query the element
const horizontalResizer = document.getElementById('dragMeHorizontal');
const leftSide = horizontalResizer.previousElementSibling;
const rightSide = horizontalResizer.nextElementSibling;
// The current position of mouse
let x = 0;
let y = 0;
let leftWidth = 0;
// Handle the mousedown event
// that's triggered when user drags the resizer
const mouseDownHandler = function(e) {
// Get the current mouse position
x = e.clientX;
y = e.clientY;
leftWidth = leftSide.getBoundingClientRect().width;
// Attach the listeners to `document`
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
};
const mouseMoveHandler = function(e) {
// How far the mouse has been moved
const dx = e.clientX - x;
const dy = e.clientY - y;
const newLeftWidth = ((leftWidth + dx) * 100) / horizontalResizer.parentNode.getBoundingClientRect().width;
leftSide.style.width = `${newLeftWidth}%`;
horizontalResizer.style.cursor = 'col-resize';
document.body.style.cursor = 'col-resize';
leftSide.style.userSelect = 'none';
leftSide.style.pointerEvents = 'none';
rightSide.style.userSelect = 'none';
rightSide.style.pointerEvents = 'none';
};
const mouseUpHandler = function() {
horizontalResizer.style.removeProperty('cursor');
document.body.style.removeProperty('cursor');
leftSide.style.removeProperty('user-select');
leftSide.style.removeProperty('pointer-events');
rightSide.style.removeProperty('user-select');
rightSide.style.removeProperty('pointer-events');
// Remove the handlers of `mousemove` and `mouseup`
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
};
// Attach the handler
horizontalResizer.addEventListener('mousedown', mouseDownHandler);
});
// Tab Changer
function changeActiveTab(tabNumber) {
const allOtherTabs = document.getElementsByClassName("tab")
const hideElements = [...allOtherTabs].filter((element, index) => index !== tabNumber)
const selectedTab = document.getElementsByClassName("tab")[tabNumber]
hideElements.forEach(element => element.classList.add("hidden"));
selectedTab.classList.remove("hidden");
}
// handle tab 1 select
document.getElementById("tab1").addEventListener('mousedown', () => {
changeActiveTab(0)
})
// handle tab 2 select
document.getElementById("tab2").addEventListener('mousedown', () => {
changeActiveTab(1)
})
// handle tab 3 select
document.getElementById("tab3").addEventListener('mousedown', () => {
changeActiveTab(2)
})
.resizer[data-direction='vertical'] {
background-color: #cbd5e0;
cursor: ns-resize;
height: 10px;
width: 100%;
}
.button__container {
margin: 6px 12px;
display: flex;
flex-direction: row;
}
.tab__internal {
max-height: 18%;
}
button {
background-color: orange;
border: none;
padding: 8px;
min-width: 150px;
margin: 1px;
border: 1px solid teal;
}
.main__container {
display: flex;
flex-direction: column;
justify-content: center;
border: 1px solid blue;
}
.sub__container {
height: 250px;
/* Misc */
}
#tab__2 {
background-color: green;
}
#tab__3 {
background-color: teal;
}
.container__top {
/* Initial height */
height: 100%;
/* Misc */
display: flex;
flex-direction: row;
background-color: green;
}
.hidden {
display: none;
}
.tabs__container {
background-color: blue;
height: 100px;
max-height: calc(100% - 100px);
min-height: 50px;
}
.tab__contents {
height: 100%;
}
.container__bottom {
/* Take the remaining height */
width: 100%;
height: 150px;
min-height: 100px;
max-height: calc(100% - 50px);
/* Misc */
display: flex;
flex-direction: column;
background-color: red;
}
.container__left {
width: 50%;
height: 100%;
/* Misc */
display: flex;
background-color: goldenrod;
}
.resizer__horizontal {
background-color: #cbd5e0;
cursor: ew-resize;
height: 100%;
width: 5px;
}
.container__right {
/* Take the remaining width */
flex: 1;
height: 100%;
/* Misc */
display: flex;
background-color: purple;
}
<html lang="en">
<head>
<meta charset="utf-8" />
<title>HTML DOM - Create resizable split views</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/demo.css" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter&family=Source+Code+Pro&display=swap" />
</head>
<body>
<div class="main__container">
<h3>Main Container</h3>
<div class="button__container">
<button class="tab_selector" id="tab1">Tab 1</button>
<button class="tab_selector" id="tab2">Tab 2</button>
<button class="tab_selector" id="tab3">Tab 3</button>
</div>
</div>
<div class="sub__container">
<div class="tabs__container">
<div class="container__top tab" id="tab__1">
<div class="container__left">
<div class="tab__contents">
<div class="tab__internal">stuff</div>
<div class="tab__internal">stuff</div>
<div class="tab__internal">stuff</div>
<div class="tab__internal">stuff</div>
</div>
</div>
<div class="resizer__horizontal" id="dragMeHorizontal"></div>
<div class="container__right tab__contents">Right</div>
</div>
<div class="container__top tab hidden" id="tab__2">
<div class="tab-contents">Tab 2</div>
</div>
<div class="container__top tab hidden" id="tab__3">
<div class="tab-contents">Tab </div>
</div>
</div>
<div class="resizer" data-direction="vertical"></div>
<div class="container__bottom">
<h4>Bottom</h4>
<p>Stuff up in here.</p>
</div>
</div>
</body>
</html>

Related

Display stars rating around rounded profile image [CSS]

Hi guys i'm creating rating system and i want to display the stars elements around profile image. I have profile image set to border-radius 50% which makes it rounded, but i'm struggle to set the div with the rates on the bottom of the profile image, what i'm looking for is something like this:
Example
What i have by now it's this:
body{
box-sizing: border-box;
margin: 0 auto;
background-color: #fff;
}
.avatar-inner{
width: 100px;
height: 100px;
}
.avatar{
width: 100%;
border-radius: 50%;
}
.rate-holder{
font-size: 25px;
color: #fff;
background-color: #000;
}
<div class="avatar-holder">
<div class="avatar-inner">
<img class="avatar" src="https://i.ibb.co/bmfXcFw/avatar.png" alt="" srcset="">
<div class="rate-holder">
<span>*</span>
</div>
</div>
</div>
[1]
As #RenevanderLende mentioned in comments for doing that you can use
transform:rotate() translateX();
Here's an example:
and I should mention that in provided example you have to set icon
sizes and their margins manually to match your photo-container
dimensions
// icons count
const count = 5;
// icons size in px
const size = 18;
// icons margin in px
const marign = 4;
// icons position in deg
// e.g. if you wanna position all icons at the bottom side use: 55
// e.g. if you wanna position all icons at the left side use: 120
// e.g. if you wanna position all icons at the top side use: 240
// e.g. if you wanna position all icons at the right side use: 330
const position = 0;
// get list of all photo containers
const photoContainer = document.querySelectorAll(".photo-container");
// loop through each container and generate rating stars
[...photoContainer].forEach((container) => {
// gets radius of the container
const r = container.offsetHeight / 2;
const offset = (size / Math.PI) * -1;
const ratingContainer = document.createElement("div");
ratingContainer.className = "rating-container";
const iconsHolder = document.createElement("div");
iconsHolder.className = "icons-holder";
const pos = [];
for (let i = 0; i < count; i++) {
// creates the angles array
pos.push(i * (size + offset + marign));
// creates some holders in a circularly positioned way, to hold the rating stars
const div = document.createElement("div");
div.style.position = "absolute";
div.style.display = "block";
div.style.height = `${size}px`;
div.style.width = `${size}px`;
// sets the icons positions circularly
div.style.transform = `rotate(${pos[i]}deg) translateX(${r - size + Math.abs(offset)}px)`;
// creates the star icons
const icon = document.createElement("span");
icon.className = "icon fa fa-star";
icon.style.fontSize = `${size}px`;
// arranges icons vertically(90deg)
// remove this part to see what happens
icon.style.transform = `rotate(${pos[i] * -1}deg)`;
div.append(icon);
iconsHolder.append(div);
}
// changes the all icons position
iconsHolder.style.transform = `rotate(${position}deg)`;
ratingContainer.append(iconsHolder);
container.append(ratingContainer);
});
.photo-container {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 200px;
height: 200px;
border-radius: 50%;
overflow: hidden;
}
.rating-container {
position: absolute;
inset: 0;
}
.rating-container .icons-holder {
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.icons-holder>div {
cursor: pointer;
}
.icons-holder>div .icon {
color: orange;
}
.icons-holder>div .icon:hover {
color: darkgoldenrod;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<div class="photo-container">
<img style="width: 100%;" src="https://i.ibb.co/bmfXcFw/avatar.png" />
</div>
<div class="photo-container">
<img style="width: 100%;" src="https://i.ibb.co/bmfXcFw/avatar.png" />
</div>
Update:
[2]
You can also do it without using css transform (explanations are provided as comments in code.)
Example 1:
function ratingStars(root, options) {
// returns width and height of an element
const getRadius = (element) => {
return Math.round(element.offsetWidth / 2);
};
// takes radius, degrees returns x,y
const pos = (r, theta) => {
return {
// theta * (Math.PI / 180) converts radians to degrees
x: Math.round(r * Math.cos(theta * (Math.PI / 180))),
y: Math.round(r * Math.sin(theta * (Math.PI / 180))),
};
};
// default options
let op = {
count: 6,
icons_class: "rating-icons",
rotate: 0, // deg
clock_wise: true, // boolean
size: 28, // pt
icons_margin: 3.8, // px
edge_margin: 0, // px
};
// merges custom options with defaults
op = { ...op,
...options
};
// gets radius of the root element
const radius = getRadius(root); //pixels
if (radius) {
// creates the main holder of all icons
const rating = document.createElement("div");
rating.style.position = "absolute";
// moves the holder to the center of the root element
rating.style.left = `${radius - op.size / 2}px`;
rating.style.top = `${radius - op.size / 2}px`;
root.append(rating);
// generates the required degrees based on count and pushes to the degs
let degs = [];
// runs if the clock_wise is set on true
if (op.clock_wise == true)
for (let i = 0; i < op.count; i++) degs.push(Math.round(i * (op.size / Math.PI + op.icons_margin)));
// runs if the clock_wise is set on false
else
for (let i = 0; i < op.count; i++) degs.push(-Math.round(i * (op.size / Math.PI + op.icons_margin)));
// loops through the degrees and create a holder for each icon
degs.forEach((deg) => {
// creates a holder for each icon
let icon = document.createElement("div");
icon.style.position = "absolute";
icon.style.textAlign = "center";
// positions the holders in a circular way using pos() function that we created first
icon.style.left = `${pos(radius - op.size / 2 - op.edge_margin, deg + op.rotate).x}px`;
icon.style.top = `${pos(radius - op.size / 2 - op.edge_margin, deg + op.rotate).y}px`;
// appends the star icons the the holder
icon.innerHTML = `<span style="font-size: ${op.size * 0.75}pt;" class="${op.icons_class} fa fa-star"></span>`;
rating.append(icon);
});
}
}
const avatar = document.querySelector(".avatar");
ratingStars(avatar);
.avatar {
position: relative;
width: 300px;
height: 300px;
border-radius: 50%;
overflow: hidden;
background: red;
}
.rating-icons {
color: orange;
cursor: pointer;
transition: all 0.5s ease;
}
.rating-icons:hover {
color: yellow;
transform: scale(1.15) rotate(70deg);
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<div class="avatar">
<img src="https://i.pravatar.cc/300?img=11" style="height: 100%" />
</div>
Example 2:
(includes an example for each option)
function ratingStars(root, options) {
// returns width and height of an element
const getRadius = (element) => {
if (element.offsetHeight == element.offsetWidth) return Math.round(element.offsetWidth / 2);
else console.error("the given element isn't a circle");
};
// takes radius, degrees returns x,y
const pos = (r, theta) => {
return {
// theta * (Math.PI / 180) converts radians to degrees
x: Math.round(r * Math.cos(theta * (Math.PI / 180))),
y: Math.round(r * Math.sin(theta * (Math.PI / 180))),
};
};
// default options
let op = {
count: 6,
icons_class: "rating-icons",
rotate: 0, // deg
clock_wise: true, // boolean
size: 20, // pt
icons_margin: 8, // px
edge_margin: 0, // px
};
// merges custom options with defaults
op = { ...op,
...options
};
// gets radius of the root element
const radius = getRadius(root); //pixels
if (radius) {
// creates the main holder of all icons
const rating = document.createElement("div");
rating.style.position = "absolute";
// moves the holder to the center of the root element
rating.style.left = `${radius - op.size / 2}px`;
rating.style.top = `${radius - op.size / 2}px`;
root.append(rating);
// generates the required degrees based on count and pushes to the degs
let degs = [];
// runs if the clock_wise is set on true
if (op.clock_wise == true)
for (let i = 0; i < op.count; i++) degs.push(Math.round(i * (op.size / Math.PI + op.icons_margin)));
// runs if the clock_wise is set on false
else
for (let i = 0; i < op.count; i++) degs.push(-Math.round(i * (op.size / Math.PI + op.icons_margin)));
// loops through the degrees and create a holder for each icon
degs.forEach((deg) => {
// creates a holder for each icon
let icon = document.createElement("div");
icon.style.position = "absolute";
icon.style.textAlign = "center";
// positions the holders in a circular way using pos() function that we created first
icon.style.left = `${pos(radius - op.size / 2 - op.edge_margin, deg + op.rotate).x}px`;
icon.style.top = `${pos(radius - op.size / 2 - op.edge_margin, deg + op.rotate).y}px`;
// appends the star icons the the holder
icon.innerHTML = `<span style="font-size: ${op.size * 0.75}pt;" class="${op.icons_class} fa fa-star"></span>`;
rating.append(icon);
});
}
}
const avatars = document.querySelectorAll(".avatar");
ratingStars(avatars[0]);
ratingStars(avatars[1], {
icons_class: 'rating-icons red'
});
ratingStars(avatars[2], {
rotate: 143
});
ratingStars(avatars[3], {
clock_wise: false
});
ratingStars(avatars[4], {
size: 28
});
ratingStars(avatars[5], {
icons_margin: 20
});
ratingStars(avatars[6], {
edge_margin: 20
});
ratingStars(avatars[7], {
count: 4,
icons_class: 'rating-icons green',
rotate: 50,
clock_wise: true,
size: 30,
icons_margin: 40,
edge_margin: 15
});
ratingStars(avatars[8], {
count: 15
});
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
background: radial-gradient(circle farthest-corner at 10% 20%, rgba(90, 92, 106, 1) 0%, rgba(32, 45, 58, 1) 81.3%);
}
.avatar {
position: relative;
width: 200px;
height: 200px;
border-radius: 50%;
overflow: hidden;
background: red;
}
.rating-icons {
color: orange;
cursor: pointer;
transition: all 0.5s ease;
}
.rating-icons:hover {
color: darkgoldenrod;
transform: scale(1.15) rotate(70deg);
}
.red {
color: red;
}
.red:hover {
color: darkred;
}
.green {
color: green;
}
.green:hover {
color: yellowgreen;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<div style="display: flex">
<div class="avatar" style="width: 300px; height: 300px;">
<img src="https://i.pravatar.cc/300?random=1" style="height: 100%" />
</div>
</div>
<div style="display: flex">
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=1" style="height: 100%" />
</div>
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=2" style="height: 100%" />
</div>
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=3" style="height: 100%" />
</div>
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=5" style="height: 100%" />
</div>
</div>
<div style="display: flex">
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=6" style="height: 100%" />
</div>
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=7" style="height: 100%" />
</div>
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=8" style="height: 100%" />
</div>
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=4" style="height: 100%" />
</div>
</div>

make resizing layout css

I have a website and want it to resize sort of like this:
anyone know how to do this?
i'm here trying to help. I said sorry if i false. I got reference from w3school. maybe it can help.
<html lang="en">
<head>
<meta charset="utf-8" />
<title>HTML DOM - Create resizable split views</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/demo.css" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Inter&family=Source+Code+Pro&display=swap"
/>
<style>
.container {
display: flex;
/* Misc */
border: 1px solid #cbd5e0;
height: 16rem;
width: 100%;
}
.container__left {
/* Initially, the left takes 3/4 width */
width: 75%;
/* Misc */
align-items: center;
display: flex;
justify-content: center;
}
.resizer {
background-color: #cbd5e0;
cursor: ew-resize;
height: 100%;
width: 2px;
}
.container__right {
/* Take the remaining width */
flex: 1;
/* Misc */
align-items: center;
display: flex;
justify-content: center;
}
</style>
</head>
<body>
<div class="container">
<div class="container__left">Left</div>
<div class="resizer" id="dragMe"></div>
<div class="container__right">Right</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
// Query the element
const resizer = document.getElementById('dragMe');
const leftSide = resizer.previousElementSibling;
const rightSide = resizer.nextElementSibling;
// The current position of mouse
let x = 0;
let y = 0;
let leftWidth = 0;
// Handle the mousedown event
// that's triggered when user drags the resizer
const mouseDownHandler = function (e) {
// Get the current mouse position
x = e.clientX;
y = e.clientY;
leftWidth = leftSide.getBoundingClientRect().width;
// Attach the listeners to `document`
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
};
const mouseMoveHandler = function (e) {
// How far the mouse has been moved
const dx = e.clientX - x;
const dy = e.clientY - y;
const newLeftWidth = ((leftWidth + dx) * 100) / resizer.parentNode.getBoundingClientRect().width;
leftSide.style.width = `${newLeftWidth}%`;
resizer.style.cursor = 'col-resize';
document.body.style.cursor = 'col-resize';
leftSide.style.userSelect = 'none';
leftSide.style.pointerEvents = 'none';
rightSide.style.userSelect = 'none';
rightSide.style.pointerEvents = 'none';
};
const mouseUpHandler = function () {
resizer.style.removeProperty('cursor');
document.body.style.removeProperty('cursor');
leftSide.style.removeProperty('user-select');
leftSide.style.removeProperty('pointer-events');
rightSide.style.removeProperty('user-select');
rightSide.style.removeProperty('pointer-events');
// Remove the handlers of `mousemove` and `mouseup`
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
};
// Attach the handler
resizer.addEventListener('mousedown', mouseDownHandler);
});
</script>
</body>
</html>

Intersection Observer whenever a section is partially in view scroll smoothly to bottom of section

I am trying to create something like the fullpage.js effect.
vertical slider on scrolling for a small amount
I use Intersection Observer but any solution could help
when threshold: 0.5, go to the bottom of the section, or show the whole section in view.
https://codepen.io/Safaa_alnabhan/pen/OJOQWmX
<div class="slider">
<div class="slide1"></div>
<div class="slide2"></div>
<div class="slide3"></div>
</div>
<style>
.slider {
height: 100vh;
overflow-x:hidden;
overflow-y:scroll;
-ms-overflow-style: none;
scrollbar-width: none;
}
.slider::-webkit-scrollbar {
display: none;
}
.slide1 {
height: 100vh;
background:red;
}
.slide2 {
height: 100vh;
background:green;
}
.slide3 {
height: 100vh;
background:blue;
}
</style>
<script>
const slide1 = document.querySelector('.slide1');
const slide2 = document.querySelector('.slide2');
const slide3 = document.querySelector('.slide3');
const sliders = document.querySelectorAll('.slider');
const options = {
threshold: 0.5,
}
const callback = (entries) => {
for(const entry of entries) {
if (entry.isIntersecting) {
entry.target.scrollBy(0, 300);
}
}
};
const observer = new IntersectionObserver(callback, options);
sliders.forEach(slider => observer.observe(slider));
</script>

Sticky footer after complete scroll

I am trying to create a "see-also" button that is located on the bottom of the page.
When the user reaches the bottom and decides to scroll back up, I want it to stick to the bottom of the viewport.
I have been trying with position:sticky but then it is already sticked to the bottom of the viewport when the page just loaded. I only want this after a complete scroll down.
Any clues?
Thanks in advance.
This is an example with javascript (see result sticky button on scroll top
const DIRECTION_BOTTOM = 1;
const DIRECTION_TOP = 0;
let previousScroll = 0;
let direction = scrollY === 0 ? DIRECTION_BOTTOM : DIRECTION_TOP;
window.addEventListener('scroll', function(){
const scrollY = window.scrollY;
if(direction === DIRECTION_TOP && previousScroll < scrollY){
direction = DIRECTION_BOTTOM;
// remove sticky
document.getElementById("sticky").classList.remove("show");
}
else if(direction === DIRECTION_BOTTOM && previousScroll > scrollY ){
direction = DIRECTION_TOP;
// Add sticky
document.getElementById("sticky").classList.add("show");
}
previousScroll = scrollY;
})
You can create this functionality with JQuery by creating a function which calculates when an element is in the viewport. If the button enters the viewport, add a class which makes the element position: sticky. There are different ways to approach this problem but one solution is something like this:
$.fn.isInViewport = function() {
var elementTop = $(this).offset().top;
var elementBottom = elementTop + $(this).outerHeight();
var viewportTop = $(window).scrollTop();
var viewportBottom = viewportTop + $(window).height();
return elementBottom > viewportTop && elementTop < viewportBottom;
};
$(window).on("scroll", function() {
if($('#button').isInViewport()) {
$('#button').addClass('sticky');
}
});
body {
text-align: center;
}
.button {
padding: 6px 12px;
}
.div {
width: 100%;
height: 250px;
color: #fff;
}
.div1 {
background: blue;
}
.div2 {
background: red;
}
.div3 {
background: purple;
}
.sticky {
position: sticky;
position: -webkit-sticky;
position: -moz-sticky;
position: -ms-sticky;
position: -o-sticky;
height: 100%;
bottom: 5px;
}
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<div class="div div1">Filler div 1</div>
<div class="div div2">Filler div 2</div>
<div class="div div3">Filler div 3</div>
<button type="button" class="button" id="button">See Also</button>
Scrambled everything together and this is working now:
window.onscroll = function(ev) {
if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
document.getElementById("see-also").classList.add("sticky");
}
};
Thanks you everyone

CSS: Make children inside parent responsive

So I am not using any CSS framework like bootstrap to get responsiveness out of the box which is why I am having trouble making responsive layout.
Please see jsbin
I essentially what to auto-resize colorful boxes based on browser window size eg that should shrink or grow automatically based on window size. Colorful boxes inside their parent should always be in horizontal row but should be able to adjust their width and height like this example.
I tried using flex-wrap: nowrap; but it didn't do the trick :(
Please note that colorful boxes are using position:absolute with parent's position being relative. I am also adding left css property to these boxes via JavaScript to change their position for the sake of sliding animation.
function Carousel(options) {
options = options || {};
// options vars
let speed = options.speed || 1; // animation speed in seconds
let width = options.width || 200;
let height = options.height || 100;
let space = options.space || 30;
// other vars
let container = document.querySelector('.carousel-container .carousel');
let slides = container.querySelectorAll('.carousel-item');
let curSlide = null;
let prevSlide = null;
let nextSlide = null;
if (areSlidesPresent()) {
setup();
}
// functions //
function setup() {
// we assume first slide to be current one as per UI requirements
//slides[0].classList.add("current");
curSlide = slides[0];
// we assume second slide to be next as per UI requirements
nextSlide = slides[1];
// we assume last slide to be prev as per UI requirements
prevSlide = slides[slides.length - 1];
// position elements horizontally
positionSlides();
}
function areSlidesPresent() {
return slides.length > 0;
}
this.getCurrentSlide = function() {
return curSlide;
}
this.getNextSlide = function() {
return nextSlide;
}
this.getPreviousSlide = function() {
return prevSlide;
}
this.setNextSlide = function() {
if (areSlidesPresent()) {
let allSlides = [];
// build new order of slides
allSlides.push(nextSlide);
// middle ones
for (let i = 2; i < slides.length; i++) {
allSlides.push(slides[i]);
}
allSlides.push(curSlide);
// now add to DOM after cleaning previous slide order
for (let i = 0; i < allSlides.length; i++) {
container.appendChild(allSlides[i]);
}
slides = allSlides;
setup();
}
}
this.setPreviousSlide = function() {
if (areSlidesPresent()) {
let allSlides = [];
// build new order of slides
allSlides.push(prevSlide);
allSlides.push(curSlide);
// middle ones
for (let i = 1; i < slides.length - 1; i++) {
allSlides.push(slides[i]);
}
// now add to DOM after cleaning previous slide order
for (let i = 0; i < allSlides.length; i++) {
container.appendChild(allSlides[i]);
}
slides = allSlides;
setup();
}
}
function positionSlides() {
curSlide.style.marginLeft = '0px';
for (let i = 0; i < slides.length; i++) {
slides[i].querySelector('.carousel-content').style.width = (width) + 'px';
slides[i].querySelector('.carousel-content').style.height = (height) + 'px';
let elementWidth = getStyle(nextSlide, 'width');
if (i === 0) {
slides[i].style.zIndex = -10;
//slides[i].style.opacity = '1';
slides[i].querySelector('.carousel-content').style.width = (width + 50) + 'px';
slides[i].querySelector('.carousel-content').style.height = (height + 50) + 'px';
} else {
slides[i].style.zIndex = 0;
//slides[i].style.opacity = '0.7';
}
if (i > 0) {
slides[i].style.marginLeft = (space * 2) + 'px';
elementWidth = parseInt(elementWidth, 10) + space;
}
slides[i].style.transition = speed + 's';
slides[i].style.left = (elementWidth * i) + 'px';
}
}
function getStyle(el, prop) {
return window.getComputedStyle(el, null).getPropertyValue(prop)
.replace('px', '')
.replace('em', '');
}
}
// utility
function log(text) {
console.log(text);
}
var options = {
speed: 1, // animation speed
width: 250, // slide width
height: 150, // slide height
space: 25 // space in px between slides
};
var carousel = new Carousel(options);
function selectCurrent() {
log(carousel.getCurrentSlide());
}
function selectNext() {
carousel.setNextSlide();
}
function selectPrev() {
carousel.setPreviousSlide();
}
.carousel-container {
width: auto;
height: auto;
margin: 25px;
display: flex;
align-items: center;
justify-content: center;
}
.carousel {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.carousel .carousel-item {
position: absolute;
transition: transform .5s ease-in-out;
color: #fff;
margin-left: 10px;
-webkit-box-reflect: below 10px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(70%, transparent), to(rgba(255, 255, 255, 0.2)));
}
.carousel .carousel-item:first-child .carousel-content {
opacity: 1;
}
.carousel .carousel-item .carousel-title {
font-size: 24px;
text-align: center;
}
.carousel .carousel-item .carousel-content {
font-size: 18px;
font-weight: bold;
border: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
}
/* temp css below */
body {
background: #2C374A;
padding-top: 150px;
}
.navigation {
display: flex;
align-items: center;
justify-content: center;
margin-top: 150px;
}
.button {
color: #444;
padding: 10px;
width: 60px;
cursor: pointer;
background: #CCC;
text-align: center;
font-weight: bold;
border-radius: 5px;
border-top: 1px solid #FFF;
box-shadow: 0 5px 0 #999;
transition: box-shadow 0.1s, top 0.1s;
margin: 10px;
}
.button:hover,
.button:hover {
color: #000;
}
.button:active,
.button:active {
top: 104px;
box-shadow: 0 1px 0 #999;
}
<div class="carousel-container">
<div class="carousel">
<div class="carousel-item">
<div class="carousel-title">Make a Call</div>
<div class="carousel-content" style="background:#0E6DE8;border:10px solid #78B1FA">Slide One</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Message</div>
<div class="carousel-content" style="background:#D90080;border:10px solid #E357A9">Slide Two</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Picture</div>
<div class="carousel-content" style="background:#FEC601;border:10px solid #FFDD64">Slide Three</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Video</div>
<div class="carousel-content" style="background:#3DB365;border:10px solid #90E0AB">Slide Four</div>
</div>
</div>
</div>
<div class="navigation">
<div class="button" onclick="selectNext()">Next</div>
<div class="button" onclick="selectCurrent()">Select</div>
<div class="button" onclick="selectPrev()">Prev</div>
</div>
Problem here was:
Width was hard-coded in your JS, so if width is in px it can't be responsive.
By applying position:absolute to you carousel-item, it forced the children to get out of the box.
What I did:
Got rid of the static width and other functionalities related to width from your JS
Removed position:absolute from carousel-item
Let me know if this is what you are expecting.
function Carousel(options) {
options = options || {};
// options vars
let speed = options.speed || 1; // animation speed in seconds
// let width = options.width || 100;
let height = options.height || 100;
let space = options.space || 30;
// other vars
let container = document.querySelector('.carousel-container .carousel');
let slides = container.querySelectorAll('.carousel-item');
let curSlide = null;
let prevSlide = null;
let nextSlide = null;
if (areSlidesPresent()) {
setup();
}
// functions //
function setup() {
// we assume first slide to be current one as per UI requirements
//slides[0].classList.add("current");
curSlide = slides[0];
// we assume second slide to be next as per UI requirements
nextSlide = slides[1];
// we assume last slide to be prev as per UI requirements
prevSlide = slides[slides.length - 1];
// position elements horizontally
positionSlides();
}
function areSlidesPresent() {
return slides.length > 0;
}
this.getCurrentSlide = function() {
return curSlide;
}
this.getNextSlide = function() {
return nextSlide;
}
this.getPreviousSlide = function() {
return prevSlide;
}
this.setNextSlide = function() {
if (areSlidesPresent()) {
let allSlides = [];
// build new order of slides
allSlides.push(nextSlide);
// middle ones
for (let i = 2; i < slides.length; i++) {
allSlides.push(slides[i]);
}
allSlides.push(curSlide);
// now add to DOM after cleaning previous slide order
for (let i = 0; i < allSlides.length; i++) {
container.appendChild(allSlides[i]);
}
slides = allSlides;
setup();
}
}
this.setPreviousSlide = function() {
if (areSlidesPresent()) {
let allSlides = [];
// build new order of slides
allSlides.push(prevSlide);
allSlides.push(curSlide);
// middle ones
for (let i = 1; i < slides.length - 1; i++) {
allSlides.push(slides[i]);
}
// now add to DOM after cleaning previous slide order
for (let i = 0; i < allSlides.length; i++) {
container.appendChild(allSlides[i]);
}
slides = allSlides;
setup();
}
}
function positionSlides() {
curSlide.style.marginLeft = '0px';
for (let i = 0; i < slides.length; i++) {
// slides[i].querySelector('.carousel-content').style.width = (width) + 'px';
slides[i].querySelector('.carousel-content').style.height = (height) + 'px';
let elementWidth = getStyle(nextSlide, 'width');
if (i === 0) {
slides[i].style.zIndex = -10;
//slides[i].style.opacity = '1';
// slides[i].querySelector('.carousel-content').style.width = (width + 50) + 'px';
slides[i].querySelector('.carousel-content').style.height = (height + 50) + 'px';
} else {
slides[i].style.zIndex = 0;
//slides[i].style.opacity = '0.7';
}
if (i > 0) {
slides[i].style.marginLeft = (space * 2) + 'px';
// elementWidth = parseInt(elementWidth, 10) + space;
}
slides[i].style.transition = speed + 's';
// slides[i].style.left = (elementWidth * i) + 'px';
}
}
function getStyle(el, prop) {
return window.getComputedStyle(el, null).getPropertyValue(prop)
.replace('px', '')
.replace('em', '');
}
}
// utility
function log(text) {
console.log(text);
}
var options = {
speed: 1, // animation speed
width: 250, // slide width
height: 150, // slide height
space: 25 // space in px between slides
};
var carousel = new Carousel(options);
function selectCurrent() {
log(carousel.getCurrentSlide());
}
function selectNext() {
carousel.setNextSlide();
}
function selectPrev() {
carousel.setPreviousSlide();
}
.carousel-container {
height: auto;
margin: 25px;
display: flex;
}
.carousel {
flex: 1;
height: 100%;
width: 100vh;
/* overflow:hidden; */
display: flex;
align-items: center;
justify-content: center;
}
.carousel .carousel-item {
transition: transform .5s ease-in-out;
color: #fff;
flex: 1;
margin-left: 10px;
-webkit-box-reflect: below 10px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(70%, transparent), to(rgba(255, 255, 255, 0.2)));
}
.carousel .carousel-item:first-child .carousel-content {
opacity: 1;
}
.carousel .carousel-item .carousel-title {
font-size: 24px;
text-align: center;
}
.carousel .carousel-item .carousel-content {
font-size: 18px;
font-weight: bold;
border: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
}
/* temp css below */
body {
background: #2C374A;
}
.navigation {
display: flex;
align-items: center;
justify-content: center;
}
.button {
color: #444;
padding: 10px;
width: 60px;
cursor: pointer;
background: #CCC;
text-align: center;
font-weight: bold;
border-radius: 5px;
border-top: 1px solid #FFF;
box-shadow: 0 5px 0 #999;
transition: box-shadow 0.1s, top 0.1s;
margin: 10px;
}
.button:hover,
.button:hover {
color: #000;
}
.button:active,
.button:active {
box-shadow: 0 1px 0 #999;
}
<div class="navigation">
<div class="button" onclick="selectNext()">Next</div>
<div class="button" onclick="selectCurrent()">Select</div>
<div class="button" onclick="selectPrev()">Prev</div>
</div>
<div class="carousel-container">
<div class="carousel">
<div class="carousel-item">
<div class="carousel-title">Make a Call</div>
<div class="carousel-content" style="background:#0E6DE8;border:10px solid #78B1FA">Slide One</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Message</div>
<div class="carousel-content" style="background:#D90080;border:10px solid #E357A9">Slide Two</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Picture</div>
<div class="carousel-content" style="background:#FEC601;border:10px solid #FFDD64">Slide Three</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Video</div>
<div class="carousel-content" style="background:#3DB365;border:10px solid #90E0AB">Slide Four</div>
</div>
</div>
</div>