Scale transition in four divs - javascript

This question is related to one that i have already created transition-in-div . I didnot get answer for my next issue there so i decided to create new question.
I have four boxes and i want the transition effect in all four boxes.
What i want is whenever i click on any box, the width of that box must increase from its side to the left and right to fit the full width. Right now it only fills some portion of width.
My Code is
<html>
<head>
<title>Transition</title>
<style type="text/css">
.container {
display: flex;
justify-content: space-between;
}
.box {
width:20%;
height: 200px;
transition: transform .5s;
transform-origin: 0 0;
}
#first {
background-color: red;
}
#second {
background-color: green;
transform-origin: 25% 75%;
}
#third {
background-color: aqua;
transform-origin: center center;
}
#fourth {
background-color: blue;
transform-origin: 100% 0;
}
.scale {
transform: scaleX(4);
}
</style>
</head>
<body>
<div class="container">
<div id="first" class="box"></div>
<div id="second" class="box"></div>
<div id="third" class="box"></div>
<div id="fourth" class="box"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
var containerWidth = $(".container").width();
$(".box").click(function() {
var id = $(this).attr("id");
$(this).addClass('scale');
});
});
</script>
Jsfiddle

There's a small mathematical error, you are scaling each div to 4x when their size is 20% so their new size is now 80% instead of the full 100% width.
Please consider the following fiddle: https://jsfiddle.net/m157u2yw/7/
For previewing purposes I've made it so if you click on an expanded box it resets back so you can quickly play with it.
I'm using width instead of scale as it will be useful in case these squares actually have some content inside (scaling would distort it).
I'm also adding another class .scale-down to the not-clicked divs to make sure they also animate out leaving the full space to the expanded one.

Just tweak around your CSS a lil bit:
Since your .box width is 20%, your scaleX() is 5,
Then just go ahead and fix your Transform-origins so it covers out correctly:
https://jsfiddle.net/m157u2yw/8/
.box {
width:20%;
height: 200px;
transition: transform .5s;
transform-origin: 0 0;
}
#first {
background-color: red;
}
#second {
background-color: green;
transform-origin: 33.33%;
}
#third {
background-color: aqua;
transform-origin: 66.66%;
}
#fourth {
background-color: blue;
transform-origin: 100%;
}
.scale {
transform: scaleX(5);
}

Why not put the boxes in containers and animate the width, something like this:
https://jsfiddle.net/pt1vk0c1/
<div class="container">
<div id="first" class="box-container">
<div class="box"> </div>
</div>
<div id="second" class="box-container">
<div class="box"> </div>
</div>
<div id="third" class="box-container">
<div class="box"> </div>
</div>
<div id="fourth" class="box-container">
<div class="box"> </div>
</div>
</div>
.container {
display: flex;
justify-content: space-between;
}
.box-container {
width:25%;
height: 200px;
}
.box {
width:80%;
height: 200px;
transition: width .5s;
transform-origin: 0 0;
}
#first .box {
background-color: red;
}
#second .box {
background-color: green;
transform-origin: 25% 75%;
}
#third .box {
background-color: aqua;
transform-origin: center center;
}
#fourth .box {
background-color: blue;
transform-origin: 100% 0;
}
.scale {
width:100%;
}

Here's a solution that will work regardless of the number of boxes or their width. Better to avoid any magic numbers if possible.
Transition width instead of transform. You won't need any transform origins and it will work with any number of boxes regardless of the box size.
To make the width of the other boxes 0. You can add a class to the container.
Than use
.container.open .box:not(.scale) {
width: 0;
}
to set the width of any box without the class .scale to 0
http://codepen.io/flurrd/pen/xqmwLN
CSS
.container {
display: flex;
justify-content: space-between;
}
.box {
width: 20%;
height: 200px;
transition: width .5s;
background-color: tomato;
}
.box:nth-child(odd) {
background-color: aquamarine;
}
.scale {
width: 100%;
}
.container.open .box:not(.scale) {
width: 0;
}
JS
var containerWidth = $(".container").width();
$(".box").click(function() {
var id = $(this).attr("id");
$(this).toggleClass('scale');
$(".container").toggleClass('open')
});

Related

Make adjacent div responsive to sibling's transformation

I have three inline-block divs on my page (see JSFiddle):
Div #one contains a button 'Show' and is absolutely positioned so that it overlaps the div #two. When 'Show' is clicked, div #two slides out from under #one using translateX, like so:
When this happens, I would like to push div #three down so that it appears just below div #two, like so:
I'm not sure how to go about achieving this using pure CSS that doesn't involve moving #three along the Y-axis using #three { transform: translateY(...) }. I was wondering if translateX is the wrong approach here since it does not disturb the position of neighbouring elements, but I don't know what to use in its place.
As I have already stated in the comment section: It really depends on what your final goal is and what content you put in your divs - how everything is structured.
I feel like this is more of a XY-problem. I.e. the design-choice demands for a special case/solution that could be solved in another way so that the "hacky" solution does not have to exist in the first place.
Nevertheless, since you have asked for it I give you a solution for this specific problem:
const container = document.querySelector('.container');
const slide = document.getElementById('show');
const done = document.getElementById('hide');
const two = document.getElementById('two');
const right = document.querySelector('.right');
show.addEventListener('click', function() {
two.classList.add('show');
right.classList.add('shift');
});
hide.addEventListener('click', function() {
two.classList.remove('show');
setTimeout(function() {
right.classList.remove('shift');
}, 1000)
});
.left,
.right {
position: relative;
height: 200px;
margin-top: 5px;
display: inline-block;
border: 1px solid black;
float: left;
}
.left {
width: 100px;
}
.right {
width: 200px;
margin-left: 10px;
transform: translateX(0);
}
.right.shift {
clear: left;
display: block;
float: none;
transform: translateX(100px);
}
#one,
#two {
height: 100%;
}
#one {
background-color: lightblue;
position: absolute;
z-index: 1;
}
#two {
background-color: yellow;
transform: translateX(0);
transition: transform 1s;
}
#two.show {
transform: translateX(100%);
}
<div class="left">
<div id="one">
Click 'Show' to show panel 2
<button type='button' id='show'>Show</button>
</div>
<div id="two">
Click 'Hide' to hide panel 2
<button type='button' id='hide'>Hide</button>
</div>
</div>
<div class="right">Some other content</div>
Alternative
You could implement a spoiler section that you can toggle to display more information if it is desired.
const spoilerBtn = document.getElementById('spoiler-btn');
const spoiler = document.getElementById('spoiler');
spoilerBtn.addEventListener('click', function() {
spoiler.classList.toggle('show');
});
.left,
.right {
position: relative;
height: 200px;
margin-top: 5px;
display: inline-block;
border: 1px solid black;
float: left;
}
.left {
width: 100px;
}
.right {
width: 200px;
margin-left: 10px;
}
#spoiler {
background-color: tomato;
display: none;
}
#spoiler.show {
display: block;
}
<div class="left">Aside text here</div>
<div class="right">
Toggleable section: <button id="spoiler-btn">toggle</button>
<div id="spoiler">This content can be toggled</div>
<p>Some other content</p>
</div>

Make content overflow

I'm trying to make something where I need to duplicate all the entries (multiple times) and then later I would like to make it spin and land on a colour slowly, etc. I'm now just getting stuck at duplicating the colours, how can I make it so the new colours are overflowing, without doubling the width?
I want it so that the colours go out of the wrapper div. Now they are just distributing themselves.
Any ideas?
$(document).on("click", ".duplicate", function() {
var $wrapper = $('.wrapper .inner');
$wrapper.find('.color').each(function() {
$wrapper.append($(this).clone());
});
});
.wrapper {
width: 75%;
margin: 12px auto;
height: 26px;
border-radius: 6px;
overflow: hidden;
position: relative;
}
.wrapper .inner {
width: 100%;
height: 100%;
position: absolute;
display: flex;
}
.wrapper .color {
width: 100%;
height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="inner">
<div class="color" style="background:red;width:231%"></div>
<div class="color" style="background:purple;width:111%"></div>
<div class="color" style="background:orange;width:91%"></div>
</div>
</div>
<button class='duplicate'>
Duplicate
</button>
In order to have two items in the same position in document flow you need to wrap them in a parent with position:relative and give one of them position:absolute; top:0;left:0. Also note that if your element doesn't have any content, you might need to define it's height and width. To make it same size as parent, you can give it top:0;bottom:0;left:0;right:0;.
Here's a demo started from your fiddle. You might want to inspect DOM after you press "Duplicate". I made it revert to original, so you can do it multiple times.
But do note your question is currently unclear. I'm afraid you lost me at "to make it spin and land on a colour slowly". It's truly poetic, but won't get you very far on SO...
I guess you are simply over complicating this. All what you need is a reapeated linear-gradient like this:
.wrapper {
width: 75%;
margin: 12px auto;
position: relative;
}
.wrapper .inner {
width: 100%;
height: 25px;
display: flex;
border-radius: 6px;
overflow: hidden;
}
.wrapper .color {
width: 100%;
height: 100%;
}
.new {
margin-top:5px;
height:25px;
border-radius: 6px;
background-image:linear-gradient(to right,red,red 54%,purple 54%, purple 80%,orange 0);
background-size:100% 100%;
animation:change 5s linear infinite alternate;
}
#keyframes change {
from {
background-position:0 0;
}
to {
background-position:-1000px 0;
}
}
<div class="wrapper">
<div class="inner">
<div class="color" style="background:red;width:231%"></div>
<div class="color" style="background:purple;width:111%"></div>
<div class="color" style="background:orange;width:91%"></div>
</div>
<div class="new"></div>
</div>

How to set when waypoints triggers

I am trying to figure out how I can trigger a waypoints function. Right now this function starts when my info div is at the very top of the screen. Ideally, I want this to start when the user's bottom of the screen just gets to the info-box section. I am unsure of how I can even modify when the event triggers.
Also, for some reason the info-boxes aren't transitions to the right like I am attempting. They just transition into a fade with now horizontal movement. What is wrong with what I am trying?
var $info_show = $('#info');
$info_show.waypoint(function () {
$('.info-box').addClass("fadeShow");
});
#info {
max-width: 100%;
height: auto;
padding: 300px 20%;
}
.info-box {
border: 1px solid black;
padding: 50px;
background: #00f;
color: #fff;
display: inline;
margin: 0 100px;
transition: 1s;
opacity: 0;
}
.info-box.fadeShow {
opacity: 1;
transform: translateX(150px);
}
<script src="https://leaverou.github.io/prefixfree/prefixfree.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="info">
<div class="info-box">Red</div>
<div class="info-box">Blue</div>
<div class="info-box">Green</div>
</div>

CSS make div take up the rest of space

I have this setup:
<div class="parent">
<div class="moverBoy"></div>
<div class="smartBoy"></div>
</div>
The parent is a for-ever-fixed element at say 100x20.
moverBoy and smartBoy always have 20 height and are inline-block and vertical-align: top so they are next to each other with no whitespaces or text anywhere.
moverBoy's width changes either with JS or CSS animations. What I need to do is have smartBoy change his width to always take up the rest of the width so that the parent is always filled.
You can get exactly what you are looking for by floating .moverBoy and modifying the overflow of .smartBoy (Works all the way back to IE6 or so!):
window.onload = function(){
document.getElementsByClassName('moverBoy')[0].style.width = '100px';
}
body{ margin:0 }
.moverBoy{
float: left;
background:#F00;
width:300px;
transition: width 2s;
}
.smartBoy{
overflow: hidden;
background:#0F0;
}
<div class="parent">
<div class="moverBoy"> </div>
<div class="smartBoy"> </div>
</div>
Alternatively, you could have your snippet behave like a table:
window.onload = function(){
document.getElementsByClassName('moverBoy')[0].style.width = '100px';
}
body{ margin: 0; }
.parent{
display:table;
width: 100%;
}
.moverBoy{
display: table-cell;
background:#F00;
width:300px;
transition: width 2s;
}
.smartBoy{
display: table-cell;
background:#0F0;
}
<div class="parent">
<div class="moverBoy"> </div>
<div class="smartBoy"> </div>
</div>
Either way, you can change the width of the parent element or .moverBoy and .smartBoy will adjust accordingly.
You could make use of CSS3 flex. In this snippet below, hover on any of the xBoys and their width will change to 75% and the other will fill the available space. Works only in modern browsers, though.
You have to just apply your width to the .moverBoy through flex-basis property. So, flex: 1 1 75% will change its width to 75% and adjusting .smartBoy accordingly. Other properties are auto grow and shrink with 1 being yes.
Snippet:
.parent {
width: 100px; height: 20px;
border: 1px solid gray;
display: flex;
flex-direction: columns;
}
.parent > div {
flex: 1 1 0%;
transition: all 500ms;
}
.parent > div:hover {
flex: 1 1 75%;
}
.moverBoy { background-color: #f00; }
.smartBoy { background-color: #00f; }
<div class="parent">
<div class="moverBoy"></div>
<div class="smartBoy"></div>
</div>
First of all, because mover and smart are on a separate line, they automatically have whitespace inbetween. You can get around this by making them the same line, or adding comments like so:
<div class="parent">
<div class="moverBoy"></div><!--
--><div class="smartBoy"></div>
</div>
For the css, you could simply use Calc:
.moverBoy {
width:20px;
}
.smartBoy {
width: calc(100% - 20px);
}
Here is a little example of it working: http://jsfiddle.net/083pnubk/

Image Slider: Working with the widths

<body>
<div id="parent_scroll">
<div id="slider">
<div class="slides">Slide1</div>
<div class="slides">Slide2</div>
<div class="slides">Slide3</div>
</div>
</div>
</body>
<style>
#parent_scroll{
width: 800px;
height: 350px;
border: 1px solid grey;
margin-left: auto;
margin-right: auto;
overflow: hidden;
position: relative;
}
#slider{
width: 2430px;
border: 1px solid green;
height: 350px;
position: absolute;
}
.slides{
width: 800px;
height: 350px;
border: 1px dotted blue;
float: left;
background-color: grey;
font-size: 30px;
text-align: center;
}
I am trying to implement a slide show sort of a feature. But i am not sure what logic goes into the javascript over here, i know i need to use a setInterval() function. The only part is how i would work out the width of the element with the id:"slider". Pointers would be helpful
EDIT: trying to implement this without jQuery
I see in your CSS that your widths are static, but if you were to add slides you should
calculate the #slider width using the width of .slides times the amount of slides..
Then, save your .slides width (including margin) as your offset, and animate #slider's left position using the offset..
EDIT: Actually, there's another technique I've been fiddling with so you won't have to calculate the widths, and that's using display inline-block like this:
#slider { white-space:nowrap;}
.slides { display:inline-block;}
this will automatically have all your slides on the same line and then you can animate using margins.
Let me know if that clears it up for you.. do you need a code example?
EDIT: example (using css animations)
Javascript
var slider, slides, offset, amount, _timer, _curindex = 0;
function initSlider() {
slider = document.getElementById("slider");
slides = document.getElementsByClassName("slides");
offset = slides[0].offsetWidth+2;
amount = slides.length;
slider.style.width = offset*amount;
_timer = setInterval(moveSlide, 3000);
}
function moveSlide() {
_curindex = (_curindex == amount-1) ? 0 : _curindex+1;
slider.style.left = -_curindex*offset+"px";
}
initSlider();
FIDDLE
Like this? Pure HTML CSS:
<div id="parent_scroll">
<div id="slider">
<div class="slides"><img src="http://placehold.it/350x150/ff0000/000000" alt=""></div>
<div class="slides"><img src="http://placehold.it/350x150/00ff00/000000" alt=""></div>
<div class="slides"><img src="http://placehold.it/350x150/0000ff/000000" alt=""></div>
</div>
</div>
DIV#parent_scroll{
width: 350px;
height: 150px;
overflow: hidden;
}
DIV#slider{
position: relative;
width: 1050px;
animation: slideme 5s infinite;
-webkit-animation: slideme 5s infinite;
}
#keyframes slideme {
0% {left: 0;}
33% {left: -350px;}
67% {left: -700px;}
100% {left: 0;}
}
#-webkit-keyframes slideme {
0% {left: 0;}
33% {left: -350px;}
67% {left: -700px;}
100% {left: 0;}
}
DIV.slides{
float: left;
}
DIV#slider:before, DIV#slider:after{
display: table;
content: "";
}
DIV#slider:after{
clear: both;
}
DIV#slider{
zoom: 1
}
http://jsfiddle.net/yLTKe/3/
Add JS to make it dynamic
you should try this code
<div id="div1" class="slides" style="width:800px...">Slide1</div>`
and in js code
var slide1 = document.getElementById("div1");
//if you want to add width
slide1.style.width= parseInt(slide1.style.width) + 100 + "px";`

Categories

Resources