Two rolling shutters animation in CSS - css

I want to do animation of opening two (top and bottom) 'shutters', behind which I want to show some data (eg. number).
I am using z-index, because I want the number behind this curtain (opening shutters) to be there before curtain is open.
Animation need to be that upper stripe will shrink to the top edge and lower striper will shrink to the bottom edge. Shrink should be visible as making height of each strip lower - so from original height of 13px to 0px. At the same time upper's stripe CSS top attribute should be +=1px and lower's stripe top should be -=1px, to mimic that they are opening.
For now i have problem with making each stripe height from original value to 0px (only one of them is 'opening'). And i don't know how to change their top attributes at the same time.
When in middle of animation time, it should like below:
CSS and HTML
#wrapper {
width: 100px;
height: 30px;
border: 2px solid black;
position: relative;
top: 50px;
z-index: 2;
}
.stripe {
position: relative;
width: 98px;
height: 13px;
background: green;
z-index: 1;
border: 1px solid red;
transition: height 500ms ease-in-out;
}
.stripe:hover {
height: 0;
}
#money {
position: relative;
top: -25px;
width: 90%;
display: block;
margin: 0 auto;
z-index: 0;
text-align: center;
}
<div id="wrapper">
<div class="stripe"></div>
<div class="stripe"></div>
<input type="text" id="money" value="1200">
</div>

You should really be using position:absolute for this and relative widths and heights (percentage values). A few tricks thrown in and I think this is closer to what you were trying to achieve.
#wrapper {
width: 100px;
height: 30px;
border: 2px solid black;
position: relative;
top: 50px;
z-index: 2;
}
.stripe {
position: absolute;
width: 100%;
height: 50%;
background: green;
z-index: 1;
transition: height 500ms ease-in-out;
}
.stripe:first-child {
border-bottom: 1px solid transparent;
top: 0;
}
.stripe + .stripe {
border-top: 1px solid transparent;
bottom: 0;
}
#wrapper:hover .stripe {
height: 0;
}
#money {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 90%;
display: block;
margin: auto;
z-index: 0;
text-align: center;
height: 1.2em;
line-height: 1.2em;
}
<div id="wrapper">
<div class="stripe"></div>
<div class="stripe"></div>
<input type="text" id="money" value="1200">
</div>
To clarify what I mean by a few tricks, I used a transparent 1px border on the bottom and top of the top and bottom shutters (respectively); I used a set width and height on the input box with margin: auto to both vertically and horizontally center it; and I used the <selector> + <selector> selector (adjacent sibling selector) to differentiate between either stripe (this is fully CSS2.1 compliant and will work pretty far back for browser compatibility).
Edit:
As requested, to convert this solution to a javascript one, just replace all occurrences of :hover (there's only one in this situation) with a class (e.g. .hover-state); and toggle the class with your favorite goto event listener format. No need for more than one class in this case.
var wrapper = document.getElementById('wrapper');
wrapper.addEventListener('mouseenter', function(){
this.classList.toggle('hover-state');
});
#wrapper {
width: 100px;
height: 30px;
border: 2px solid black;
position: relative;
top: 50px;
z-index: 2;
cursor: text;
display: block;
}
.stripe {
position: absolute;
width: 100%;
height: 50%;
background: green;
z-index: 1;
transition: height 500ms ease-in-out;
}
.stripe:first-of-type {
border-bottom: 1px solid transparent;
top: 0;
}
.stripe + .stripe {
border-top: 1px solid transparent;
bottom: 0;
}
#wrapper.hover-state .stripe, input:focus ~ .stripe {
height: 0;
}
#money {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 90%;
display: block;
margin: auto;
z-index: 0;
text-align: center;
height: 1.2em;
line-height: 1.2em;
outline: none!important;
border: none;
background: transparent;
}
<label id="wrapper">
<input type="text" id="money" value="1200">
<div class="stripe"></div>
<div class="stripe"></div>
</label>

Related

Border-radius and overflow hidden with child background

I've got a problem with border-radius on wrapper that contains an overflow hidden.
I use a before pseudo element (pink background) to fill the wrapper's background. The wrapper has already a background (blue).
#wrapper {
background: blue;
border: 2px solid pink;
border-radius: 12px;
height: 90px;
overflow: hidden;
position: relative;
width: 300px;
}
#wrapper::before {
background: pink;
content: '';
display: block;
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 50%;
}
<div id="wrapper"></div>
With this example, we can see an unwanted blue pixel on the top and bottom left corner.
The pseudo element must be in position absolute to apply animation. I removed the animation for the example.
How can I fix this?
A fix is here. Apply overflow:hidden an width:300px to the outer div #container.
#container {
width: 300px;
overflow: hidden;
border-radius: 12px;
}
#wrapper {
height: 90px;
background: blue;
border-radius: 12px;
position: relative;
box-sizing: border-box;
border: 2px solid pink;
}
#wrapper::before {
background: pink;
content: '';
display: block;
height: 100%;
right: -30px;
position: absolute;
top: 0;
width: 30px;
border-radius: 50%;
transition: transform 0.3s;
}
#wrapper:hover::before {
transform: scale3D(10, 10, 1);
}
<div id="container">
<div id="wrapper"></div>
</div>
You found a really interesting rendering issue. My idea to solve it, is switch the colors and logic a little:
#wrapper {
background: pink;
border: 2px solid pink;
border-radius: 12px;
height: 90px;
overflow: hidden;
position: relative;
width: 300px;
}
#wrapper::before {
background: blue;
content: '';
display: block;
height: 100%;
right: 0;
position: absolute;
top: 0;
width: 50%;
}
<div id="wrapper"></div>

CSS transition background color without a hover

I have a div called time-box. Sometimes I will also include an additional class called countdown. If countdown is added then I would like to use a CSS transition effect so the background changes to be red over the course of 60 seconds. In other words, each second that passes the red background gets a little wider until eventually all of the green background has gone.
I have found similar posts here but they all seem to relate to hover
Here is a fiddle
https://jsfiddle.net/e2vbheew/
I don't know a "simple" way to get what you want going from left to right, but there's a way you can create it using before and after pseudoelements. The key here is I'm going to create a :before pseudoelement that has the new background that transitions across, and an :after pseudoelement that replicates the content and puts it on top of the before, so it's still visible. This required putting the content in an attribute on the div so I could reference it in the 'content' of the pseudoelement. If you had more complex content inside, you could probably do away with the :after and simply give the internal content position and z-index to make sure it's visible. Here's the resulting CSS
.time-box {
height: 27px;
text-align: center;
background-color: #25E57B;
font-size:2rem;
padding:0px;
font-size:1.2rem;
text-transform:uppercase;
padding:3px 5px 3px 5px;;
font-weight:600;
height:auto;
position: relative;
}
.time-box:before {
background-color: red;
position: absolute;
left:0;
top: 0;
height: 100%;
width: 0;
content: " ";
transition: width 60s ease;
}
.countdown:after {
content: attr(data-content);
width: 100%;
text-align: center;
height: 100%;
position: absolute;
left: 0;
top: center;
z-index: 1;
}
.countdown:before {
width:100%;
}
And updated fiddle: https://jsfiddle.net/tunzwqd7/2/
Using CSS animation property...
.time-box {
height: 27px;
text-align: center;
background-color: #25E57B;
font-size: 2rem;
padding: 0px;
font-size: 1.2rem;
text-transform: uppercase;
padding: 3px 5px 3px 5px;
font-weight: 600;
height: auto;
position: relative;
z-index: 1;
}
.time-box.countdown:before {
content: '';
width: 0;
height: 100%;
display: block;
position: absolute;
top: 0;
left: 0;
background: red;
animation: countdown 60s forwards;
z-index: -1;
}
#keyframes countdown {
0% {
width: 0;
}
100% {
width: 100%;
}
}
<div class="time-box">
12:00
</div>
<div class="time-box countdown">
<span>12:00</span>
</div>
You would need to add a maximum and a little more math to make the 100% divisible by 60, but this should get you on the right track. Currently this code updates every second and adds 1% to the progress bar width with each iteration.
var time = 0;
var bar = document.querySelector('.countdown .progress-bar');
window.setInterval(function(){
time++;
bar.style.width = time+"%";
}, 1000);
.time-box {
height: 27px;
text-align: center;
background-color: #25E57B;
font-size:2rem;
padding:0px;
font-size:1.2rem;
text-transform:uppercase;
padding:3px 5px 3px 5px;;
font-weight:600;
height:auto;
position: relative;
}
.progress-bar {
display: none;
}
.countdown .progress-bar {
display: block;
position: absolute;
left: 0;
top: 0;
bottom: 0;
background: red;
width: 0%;
z-index: 1;
transition: all 0.3s ease-out;
}
.countdown p {
z-index: 2;
position: relative;
}
<div class="time-box">
<p>12:00</p>
<div class="progress-bar"></div>
</div>
<div class="time-box countdown">
<p>12:00</p>
<div class="progress-bar"></div>
</div>

Button styling with ::after pseudo element

I am trying to style button like this:
Now I first though I could just style it with an ::after element attached to the button.
Currently I have this (using sass syntax):
button {
min-width: 230px;
border: 1px solid green;
background-color: white;
padding: 25px;
display: block;
position: relative;
z-index: 10;
&::after {
content: '';
display: block;
position: absolute;
top: 10px;
left: 10px;
width: 100%;
height: 100%;
border: 1px solid green;
background-color: white;
z-index: -2;
}
}
But this renders something which looks a little different:
The rectangle more to the right is my :afterelement.
It is indeed behind the text «Button» (without the z-Index it would just be in front), but it does not go behind the other rectangle.
How could I style this correctly?
Thanks for the help
Cheers
Remove the z-index: 10 from the button. When the parent element (button in this case) have a z-index value it becomes the root element of the stacking context, and you can't move the child under it.
You can read more about stacking context and stacking order in the great article What No One Told You About Z-Index.
button {
min-width: 230px;
border: 1px solid green;
background-color: white;
padding: 25px;
display: block;
position: relative;
}
button::after {
content: '';
display: block;
position: absolute;
top: -10px;
left: 10px;
width: 100%;
height: 100%;
border: 1px solid green;
background-color: white;
z-index: -1;
}
body {
padding: 20px;
}
<button>Button</button>
I have added a few little things to the code. but this seems to work for me. There might be a simpler way, but the flip, flip works. :)
button {
min-width: 230px;
border: 1px solid green;
background-color: white;
padding: 25px;
display: block;
position: relative;
left: 20px;
z-index: 10;
transform: rotateY(180deg);
}
button::after {
content: '';
display: block;
position: absolute;
top: 10px;
left: 10px;
width: 100%;
height: 100%;
border: 1px solid green;
background-color: white;
z-index: -1;
}
.buttonz{
transform: rotateY(180deg);
}
<button>
<div class="buttonz">
Button
</div>
</button>

Make Ribbon Appear Behind Rectangle

I am trying to create a ribbon at the beginning of a rectangle. However, I cannot figure out how to make it appear BEHIND the rectangle.
Please see this codepen: http://codepen.io/gosusheep/pen/aOqOBy
The part for creating the ribbon and putting it behind the rectangle is here:
.rectangle::before{
content: "";
width: 0;
height: 0;
display: block;
position: absolute;
z-index: -1;
border-left: 25px solid transparent;
border-right: 25px solid $blue;
border-top: 25px solid $blue;
border-bottom: 25px solid $blue;
left: -30px;
top: 10%;
}
Even with position: absolute, and z-index: -1, it appears ON TOP of the div.
Can anyone help with this?
What is happening here is that apparently, the property transform: translateX(-50%); it's "overriding" in some way the z-index. My solution is just center rectangle otherwise, for example:
.rectangle{
margin: 0 auto;
}
DEMO
The reason for your problem is not because children cannot be positioned behind their parent but because you are using a transform on the parent. Using transforms affect the stacking context like mentioned in this answer by BoltClock.
One solution would be to avoid the transform totally and use left: calc(50% - 100px) instead to position the ribbon at the center (like in the below snippet). (50% - 100px) is used as the value because 100px is half of the box width (50% is the center point of the parent).
.rectangle {
width: 200px;
height: 50px;
background-color: #8080ff;
position: relative;
left: calc(50% - 100px); /* newly added */
border: 1px #6666ff solid;
}
ul {
list-style: none;
}
li {
display: inline;
}
li + li::before {
content: " | ";
}
.container {
width: 100%;
position: relative;
}
.rectangle {
width: 200px;
height: 50px;
background-color: #8080ff;
position: relative;
left: calc(50% - 100px); /* newly added */
border: 1px #6666ff solid;
}
.rectangle::before {
content: "";
width: 0;
height: 0;
display: block;
position: absolute;
z-index: -1;
border-left: 25px solid transparent;
border-right: 25px solid #8080ff;
border-top: 25px solid #8080ff;
border-bottom: 25px solid #8080ff;
left: -30px;
top: 10%;
}
<p>put a pipe between nav elements</p>
<nav>
<ul>
<li>banana</li>
<li>woof</li>
<li>quack</li>
</ul>
</nav>
<p>Ribbon on the end of a rectangle</p>
<div class='container'>
<div class='rectangle'></div>
</div>
If in case you can't use the above solution, then you could follow the approach described below.
Assuming you don't have any other use for the ::after pseudo-element, you could use that to create the rectangle and give it a z-index higher than the ::before pseudo-element to make it appear behind the rectangle.
/* Modified */
.rectangle {
width: 200px;
height: 50px;
position: relative;
left: 50%;
transform: translateX(-50%);
}
/* Added */
.rectangle::after {
content: "";
width: 100%;
height: 100%;
top: 0px;
left: 0px;
display: block;
position: absolute;
background-color: #8080ff;
border: 1px #6666ff solid;
z-index: -1;
}
.rectangle{
padding: 4px;
box-sizing: border-box;
}
Below is a sample snippet:
ul {
list-style: none;
}
li {
display: inline;
}
li + li::before {
content: " | ";
}
.container {
width: 100%;
position: relative;
}
.rectangle::before {
content: "";
width: 0;
height: 0;
display: block;
position: absolute;
z-index: -2;
border-left: 25px solid transparent;
border-right: 25px solid #8080ff;
border-top: 25px solid #8080ff;
border-bottom: 25px solid #8080ff;
left: -30px;
top: 10%;
}
/* Modified */
.rectangle {
width: 200px;
height: 50px;
position: relative;
left: 50%;
transform: translateX(-50%);
}
/* Added */
.rectangle::after {
content: "";
width: 100%;
height: 100%;
top: 0px;
left: 0px;
display: block;
position: absolute;
background-color: #8080ff;
border: 1px #6666ff solid;
z-index: -1;
}
.rectangle{
padding: 4px;
box-sizing: border-box;
}
<p>put a pipe between nav elements</p>
<nav>
<ul>
<li>banana</li>
<li>woof</li>
<li>quack</li>
</ul>
</nav>
<p>Ribbon on the end of a rectangle</p>
<div class='container'>
<div class='rectangle'>
Some content
</div>
</div>
Solution here, look closely at z-indexes and positions
.container{
position: relative;
width: 100%;
z-index: 1;
}
.rectangle{
width: 200px;
height: 50px;
background-color: $blue;
position: absolute;
left: 50%;
border: 1px darken($blue,5%) solid;
}
.rectangle::after{
content: "";
width: 0;
height: 0;
border-left: 25px solid transparent;
border-right: 25px solid $blue;
border-top: 25px solid $blue;
border-bottom: 25px solid $blue;
left: -30px;
top: 10px;
position: absolute;
z-index: -1;
}
And your codepen edited http://codepen.io/anon/pen/mJXeed working now

Solving a div positioning issue

I have a test site here:
http://www.hugoproject.com/test.html
I'm trying to put a second row of the book icons beneath the first, but whatever I try doesn't work. To clarify the situation, the following code makes a single book icon appear:
<div class="project">
Arrow<span></span>
</div>
When I have two sets of the code, two icons appear, when there are three sets of the code three icons appear. But if I have four or more sets of the code only three icons appear! I want for the extra sets of code to make icons beneath the first three.
Also at the moment when you resize the browser window this makes the top row of icons resize dynamically. I'd like to keep this feature and make both rows of icons fit on the one page such that there is no scroll bar.
Any ideas?
HTML
<div id="content">
<div id="home-projects-wrapper">
<h1 class="home">Hello! My name is Brandon</h1>
<div id="home-projects">
<div id="projects" class="circle">
<div class="project-group">
<div class="project">
Arrow<span></span>
</div>
<div class="project">
Arrow<span></span>
</div>
<div class="project">
Arrow<span></span>
</div>
<div class="project">
Arrow<span></span>
</div>
</div>
</div>
</div>
</div>
</div>
CSS
#container {
transition: left .3s;
-moz-transition: left .3s;
-webkit-transition: left .3s;
position: absolute;
width: 100%;
height: 100%;
left: 0;
overflow-x: hidden;
}
#container.open {
left: 270px;
position: absolute;
width: 100%;
height: 100%;
transition: left .3s;
-moz-transition: left .3s;
-webkit-transition: left .3s;
overflow-x: hidden;
}
#content {
width: 80%;
max-width: 1170px;
margin: 7% auto;
position: relative;
font-size: 14px;
line-height: 22px;
color: #777777;
}
.page-template-page-templateshome-php #content {
width: auto;
margin: 0 auto;
position: static;
}
.single-post #content {
width: 60%;
}
#home-projects {
text-align: center;
overflow: hidden;
position: relative;
}
#projects {
width: 100%;
}
.project-group {
width: 100%;
height: 100%;
position: absolute;
}
.project {
float: left;
text-align: center;
width: 33.3%;
height:100%;
}
.project-link {
background-size: cover;
background-repeat: no-repeat;
background-position: center;
background-color: #adadad;
position: relative;
overflow: hidden;
display: inline-block;
width: 80%;
}
.circle .project-link, .circle .project-link .hover {
border-radius: 100%;
-moz-border-radius: 100%;
-webkit-border-radius: 100%;
}
.project-link .hexagon-top {
content: '';
display: block;
position: absolute;
left: 0;
border-style: solid;
border-bottom-color: transparent;
border-left-color: #dfdfdf;
border-right-color: #dfdfdf;
width: 0;
height: 0;
z-index: 2;
}
.project-link .hexagon-bottom {
content: '';
display: block;
position: absolute;
left: 0;
bottom: 0;
border-style: solid;
border-top-color: transparent;
border-left-color: #dfdfdf;
border-right-color: #dfdfdf;
width: 0;
height: 0;
z-index: 2;
}
.project-link .hover {
position: absolute;
width: 100%;
height: 100%;
font-size: 14px;
text-align: center;
color: #fff;
background: #ec6136;
text-decoration: none;
text-transform: uppercase;
display: block;
opacity: 0;
transition: all .3s;
-moz-transition: all .3s;
-webkit-transitin: all .3s;
}
.project-link .hover-text {
display: block;
margin-top: 45%;
}
.project-link .hover-text:after {
content: '>';
font-family: 'icon';
font-size: 12px;
margin-left: 15px;
}
.project-link:hover > .hover {
opacity: .9;
}
If you want to continue with what you have now, just remove position:absolute from .project-group
You need to define a height for your blocks, i.e.
.project {
float: left;
text-align: center;
width: 33.3%;
height: 290px;
}
.HS {
display: inline-block;
position: relative;
text-indent: -9999px;
width: 100%;
height: 290px;
background-image: url("http://www.hugoproject.com/ftp1/images/icons.png");
background-position: 0px 0px;
background-size: 800%;
}
That will not completely solve your issue though. Maybe you want to use images inside the boxes instead of a background image/icon. You can also always calculate new dimensions with JavaScript/jQuery.
I would set up a div container for the books with a set width equal to the width of the books + margins.
Then set the book divs to "float: left;" and it should put 3 books per line.
If you want to keep the auto scaling you should do all this with percentages like you are currently doing.

Resources