I have this CSS, where I want the footer div displayed after all content on the page. At this moment it doesnt show on the page, when I have the height of the page set to "auto", but if I set a height of any sorts or min-height it shows up till that height as it should. Can I do this, or do I have to set a manual height on each page? The CSS looks like this:
body
{
position: absolute;
top: 0;
left: 0;
right: 0;
height: auto;
background-image: url("background.jpg");
background-position: center;
background-repeat: no-repeat;
background-attachment: fixed;
background-size: cover;
}
/* Dette er css til vores footer div boks */
div.footer
{
position: absolute;
bottom: 0;
height: 250px;
left: 0;
right: 0;
padding: 1%;
background-color: rgb(255, 255, 255);
color: rgb(0, 0, 0);
line-height: 200%;
border: 1px solid black;
}
I have tried using flexbox, containers and grids, but it only seems to work, if I insert a manual height of the body.
Try this example:
.my-contnet element has min-height of 100% to take the full height of the page.
This way the footer is always displayed at the bottom of the page regardless of the amount of content on the page.
The content will fill the remaining space above the footer.
html,
body {
height: 100%;
margin: 0;
}
.my-contnet {
min-height: 100%;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
}
What about this?
div.header {
position: relative;
display: flex;
justify-content: center;
align-items: normal;
}
video.header {
position: relative;
width: 100%;
filter: brightness(60%);
left: 50%;
top: 50%;
transform: translate(-50%,0%);
}
div.headline {
position: absolute;
left: 50%;
border-radius: 50px;
transform: translate(-50%,150%);
}
h1.headline {
font-size: 500%;
text-align: center;
-webkit-text-stroke-width: 2px;
-webkit-text-stroke-color: black;
}
div.about {
position: relative;
background-color: rgba(255, 255, 255, 0.9);
border: solid black 2px;
border-radius: 40px;
padding: 2%;
display: flex;
align-items: flex-start;
margin-bottom: 280px;
}
table.text {
width: 60%;
padding-bottom: 1%;
}
table.img {
padding-top: 5%;
}
div.footer {
position:fixed;
}
The absolute positioning of your elements was causing the footer visibility problems.
Also, if you don't want the footer to be displayed at all times, just replace the fixed position in my example with relative - the footer will only be showing once your visitors scroll down to it. If you do that, however, be sure to remove the margin-bottom: 280px; rule from div.about selector.
Please note that these were just some quick fixes - I have not considered whether your site will look good (enough) on various resolutions (mobile, tablets, 4:3, etc).
You might want to look up some boilerplates, for example, the ones Bootstrap offers.
For me, this code works great.
Please pay attention to the link I sent you in the comments.
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<style type="text/css">
html, body {
/* IE 10-11 didn't like using min-height */
height: 100%;
}
body {
display: flex;
flex-direction: column;
}
.content {
flex: 1 0 auto; /* Prevent Chrome, Opera, and Safari from letting these items shrink to smaller than their content's default minimum size. */
padding: 20px;
background-color: lightblue;
}
.footer {
flex-shrink: 0; /* Prevent Chrome, Opera, and Safari from letting these items shrink to smaller than their content's default minimum size. */
padding: 20px;
background-color: blue;
}
</style>
</head>
<body>
<div class="content">
<h1>Sticky Footer with Flexbox</h1>
</div>
<footer class="footer">
Footer
</footer>
</body>
</html>
I want to center a div vertically with CSS. I don't want tables or JavaScript, but only pure CSS. I found some solutions, but all of them are missing Internet Explorer 6 support.
<body>
<div>Div to be aligned vertically</div>
</body>
How can I center a div vertically in all major browsers, including Internet Explorer 6?
Below is the best all-around solution I could build to vertically and horizontally center a fixed-width, flexible height content box. It was tested and worked for recent versions of Firefox, Opera, Chrome, and Safari.
.outer {
display: table;
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
}
.middle {
display: table-cell;
vertical-align: middle;
}
.inner {
margin-left: auto;
margin-right: auto;
width: 400px;
/* Whatever width you want */
}
<div class="outer">
<div class="middle">
<div class="inner">
<h1>The Content</h1>
<p>Once upon a midnight dreary...</p>
</div>
</div>
</div>
View A Working Example With Dynamic Content
I built in some dynamic content to test the flexibility and would love to know if anyone sees any problems with it. It should work well for centered overlays also -- lightbox, pop-up, etc.
The simplest way would be the following three lines of CSS:
1) position: relative;
2) top: 50%;
3) transform: translateY(-50%);
Following is an example:
div.outer-div {
height: 170px;
width: 300px;
background-color: lightgray;
}
div.middle-div {
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
<div class='outer-div'>
<div class='middle-div'>
Test text
</div>
</div>
One more I can't see on the list:
.Center-Container {
position: relative;
height: 100%;
}
.Absolute-Center {
width: 50%;
height: 50%;
overflow: auto;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
border: solid black;
}
Cross-browser (including Internet Explorer 8 - Internet Explorer 10 without hacks!)
Responsive with percentages and min-/max-
Centered regardless of padding (without box-sizing!)
height must be declared (see Variable Height)
Recommended setting overflow: auto to prevent content spillover (see Overflow)
Source: Absolute Horizontal And Vertical Centering In CSS
Now the Flexbox solution is a very easy way for modern browsers, so I recommend this for you:
.container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
background: green;
}
body,
html {
height: 100%;
}
<div class="container">
<div>Div to be aligned vertically</div>
</div>
Actually, you need two div's for vertical centering. The div containing the content must have a width and height.
#container {
position: absolute;
top: 50%;
margin-top: -200px;
/* Half of #content height */
left: 0;
width: 100%;
}
#content {
width: 624px;
margin-left: auto;
margin-right: auto;
height: 395px;
border: 1px solid #000000;
}
<div id="container">
<div id="content">
<h1>Centered div</h1>
</div>
</div>
Here is the result.
Edit 2020: only use this if you need to support old browsers like Internet Explorer 8 (which you should refuse to do 😉). If not, use Flexbox.
This is the simplest method I found and I use it all the time
(jsFiddle demo here).
Thank Chris Coyier from CSS Tricks for this article.
html, body{
height: 100%;
margin: 0;
}
.v-wrap{
height: 100%;
white-space: nowrap;
text-align: center;
}
.v-wrap:before{
content: "";
display: inline-block;
vertical-align: middle;
width: 0;
/* adjust for white space between pseudo element and next sibling */
margin-right: -.25em;
/* stretch line height */
height: 100%;
}
.v-box{
display: inline-block;
vertical-align: middle;
white-space: normal;
}
<div class="v-wrap">
<article class="v-box">
<p>This is how I've been doing it for some time</p>
</article>
</div>
Support starts with Internet Explorer 8.
After a lot of research I finally found the ultimate solution. It works even for floated elements. View Source
.element {
position: relative;
top: 50%;
transform: translateY(-50%); /* or try 50% */
}
Use the CSS Flexbox align-items property to achieve this.
html, body {
height: 100%;
}
body {
display: flex;
align-items: center;
}
<div>This is centered vertically</div>
To center the div on a page, check the fiddle link.
#vh {
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.box{
border-radius: 15px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
padding: 25px;
width: 100px;
height: 100px;
background: white;
}
<div id="vh" class="box">Div to be aligned vertically</div>
Another option is to use flex box, check the fiddle link.
.vh {
background-color: #ddd;
height: 400px;
align-items: center;
display: flex;
}
.vh > div {
width: 100%;
text-align: center;
vertical-align: middle;
}
<div class="vh">
<div>Div to be aligned vertically</div>
</div>
Another option is to use a CSS 3 transform:
#vh {
position: absolute;
top: 50%;
left: 50%;
/*transform: translateX(-50%) translateY(-50%);*/
transform: translate(-50%, -50%);
}
.box{
border-radius: 15px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
padding: 25px;
width: 100px;
height: 100px;
background: white;
}
<div id="vh" class="box">Div to be aligned vertically</div>
The easiest solution is below:
.outer-div{
width: 100%;
height: 200px;
display: flex;
border:1px solid #000;
}
.inner-div{
margin: auto;
text-align: center;
border: 1px solid red;
}
<div class="outer-div">
<div class="inner-div">
Hey there!
</div>
</div>
There are multiple ways to achieve this.
Using flex property of CSS.
Solution #1
.parent {
width: 400px;
height:200px;
background: blue;
display: flex;
align-items: center;
justify-content:center;
}
.child {
width: 75px;
height: 75px;
background: yellow;
}
<div class="parent">
<div class="child"></div>
</div>
or by using display: flex; and margin: auto;
Solution #2
.parent {
width: 400px;
height:200px;
background: blue;
display: flex;
}
.child {
width: 75px;
height: 75px;
background: yellow;
margin:auto;
}
<div class="parent">
<div class="child"></div>
</div>
show text center
Solution #3
.parent {
width: 400px;
height: 200px;
background: yellow;
display: flex;
align-items: center;
justify-content:center;
}
<div class="parent">Center</div>
Using percentage(%) height and width.
Solution #4
.parent {
position: absolute;
height:100%;
width:100%;
background: blue;
display: flex;
align-items: center;
justify-content:center;
}
.child {
width: 75px;
height: 75px;
background: yellow;
}
<div class="parent">
<div class="child"></div>
</div>
Unfortunately — but not surprisingly — the solution is more complicated than one would wish it to be. Also unfortunately, you'll need to use additional divs around the div you want vertically centered.
For standards-compliant browsers like Mozilla, Opera, Safari, etc. you need to set the outer div to be displayed as a table and the inner div to be displayed as a table-cell — which can then be vertically centered. For Internet Explorer, you need to position the inner div absolutely within the outer div and then specify the top as 50%. The following pages explain this technique well and provide some code samples too:
Vertical Centering in CSS
Vertical Centering in CSS with Unknown Height (Internet Explorer 7 compatible) (Archived article courtesy of the Wayback Machine)
There is also a technique to do the vertical centering using JavaScript. Vertical alignment of content with JavaScript & CSS demonstrates it.
If someone cares for Internet Explorer 10 (and later) only, use Flexbox:
.parent {
width: 500px;
height: 500px;
background: yellow;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
}
.centered {
width: 100px;
height: 100px;
background: blue;
}
<div class="parent">
<div class="centered"></div>
</div>
Flexbox support: http://caniuse.com/flexbox
A modern way to center an element vertically would be to use flexbox.
You need a parent to decide the height and a child to center.
The example below will center a div to the center within your browser. What's important (in my example) is to set height: 100% to body and html and then min-height: 100% to your container.
body, html {
background: #F5F5F5;
box-sizing: border-box;
height: 100%;
margin: 0;
}
#center_container {
align-items: center;
display: flex;
min-height: 100%;
}
#center {
background: white;
margin: 0 auto;
padding: 10px;
text-align: center;
width: 200px;
}
<div id='center_container'>
<div id='center'>I am center.</div>
</div>
.center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* (x, y) => position */
-ms-transform: translate(-50%, -50%); /* IE 9 */
-webkit-transform: translate(-50%, -50%); /* Chrome, Safari, Opera */
}
.vertical {
position: absolute;
top: 50%;
//left: 0;
transform: translate(0, -50%); /* (x, y) => position */
}
.horizontal {
position: absolute;
//top: 0;
left: 50%;
transform: translate(-50%, 0); /* (x, y) => position */
}
div {
padding: 1em;
background-color: grey;
color: white;
}
<body>
<div class="vertical">Vertically left</div>
<div class="horizontal">Horizontal top</div>
<div class="center">Vertically Horizontal</div>
</body>
Related: Center a Image
Centering only vertically
If you don't care about Internet Explorer 6 and 7, you can use a technique that involves two containers.
The outer container:
should have display: table;
The inner container:
should have display: table-cell;
should have vertical-align: middle;
The content box:
should have display: inline-block;
You can add any content you want to the content box without caring about its width or height!
Demo:
body {
margin: 0;
}
.outer-container {
position: absolute;
display: table;
width: 100%; /* This could be ANY width */
height: 100%; /* This could be ANY height */
background: #ccc;
}
.inner-container {
display: table-cell;
vertical-align: middle;
}
.centered-content {
display: inline-block;
background: #fff;
padding: 20px;
border: 1px solid #000;
}
<div class="outer-container">
<div class="inner-container">
<div class="centered-content">
Malcolm in the Middle
</div>
</div>
</div>
See also this Fiddle!
Centering horizontally and vertically
If you want to center both horizontally and vertically, you also need the following.
The inner container:
should have text-align: center;
The content box:
should re-adjust the horizontal text-alignment to for example text-align: left; or text-align: right;, unless you want text to be centered
Demo:
body {
margin: 0;
}
.outer-container {
position: absolute;
display: table;
width: 100%; /* This could be ANY width */
height: 100%; /* This could be ANY height */
background: #ccc;
}
.inner-container {
display: table-cell;
vertical-align: middle;
text-align: center;
}
.centered-content {
display: inline-block;
text-align: left;
background: #fff;
padding: 20px;
border: 1px solid #000;
}
<div class="outer-container">
<div class="inner-container">
<div class="centered-content">
Malcolm in the Middle
</div>
</div>
</div>
See also this Fiddle!
It can be done in two ways
body{
left: 50%;
top:50%;
transform: translate(-50%, -50%);
height: 100%;
width: 100%;
}
OR
Using flex
body {
height:100%
width:100%
display: flex;
justify-content: center;
align-items: center;
}
align-items:center; makes the content vertically center
justify-content: center;makes the content horizontally center
This is always where I go when I have to come back to this issue.
For those who don't want to make the jump:
Specify the parent container as position:relative or position:absolute.
Specify a fixed height on the child container.
Set position:absolute and top:50% on the child container to move the top down to the middle of the parent.
Set margin-top:-yy where yy is half the height of the child container to offset the item up.
An example of this in code:
<style type="text/css">
#myoutercontainer {position:relative}
#myinnercontainer {position:absolute; top:50%; height:10em; margin-top:-5em}
</style>
...
<div id="myoutercontainer">
<div id="myinnercontainer">
<p>Hey look! I'm vertically centered!</p>
<p>How sweet is this?!</p>
</div>
</div>
I just wrote this CSS and to know more, please go through: This article with vertical align anything with just 3 lines of CSS.
.element {
position: relative;
top: 50%;
transform: perspective(1px) translateY(-50%);
}
For newcomers, please try:
display: flex;
align-items: center;
justify-content: center;
The three lines of code using transform works practically on modern browsers and Internet Explorer:
.element{
position: relative;
top: 50%;
transform: translateY(-50%);
-moz-transform: translateY(-50%);
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
}
I am adding this answer since I found some incompleteness in the previous version of this answer (and Stack Overflow won't allow me to simply comment).
'position' relative messes up the styling if the current div is in the body and has no container div. However 'fixed' seems to work, but it obviously fixes the content in the center of the viewport
Also I used this styling for centering some overlay divs and found that in Mozilla all elements inside this transformed div had lost their bottom borders. Possibly a rendering issue. But adding just the minimal padding to some of them rendered it correctly. Chrome and Internet Explorer (surprisingly) rendered the boxes without any need for padding
CSS Grid
body, html { margin: 0; }
body {
display: grid;
min-height: 100vh;
align-items: center;
}
<div>Div to be aligned vertically</div>
.center{
display: grid;
place-items: center;
}
The answer from Billbad only works with a fixed width of the .inner div.
This solution works for a dynamic width by adding the attribute text-align: center to the .outer div.
.outer {
position: absolute;
display: table;
width: 100%;
height: 100%;
text-align: center;
}
.middle {
display: table-cell;
vertical-align: middle;
}
.inner {
text-align: center;
display: inline-block;
width: auto;
}
<div class="outer">
<div class="middle">
<div class="inner">
Content
</div>
</div>
</div>
Just do it: Add the class at your div:
.modal {
margin: auto;
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
height: 240px;
}
And read this article for an explanation. Note: Height is necessary.
I did it with this (change width, height, margin-top and margin-left accordingly):
.wrapper {
width: 960px;
height: 590px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -295px;
margin-left: -480px;
}
<div class="wrapper"> -- Content -- </div>
Not answering for browser compatibility but to also mention the new Grid and the not so new Flexbox feature.
Grid
From: Mozilla - Grid Documentation - Align Div Vertically
Browser Support: Grid Browser Support
CSS:
.wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 10px;
grid-auto-rows: 200px;
grid-template-areas:
". a a ."
". a a .";
}
.item1 {
grid-area: a;
align-self: center;
justify-self: center;
}
HTML:
<div class="wrapper">
<div class="item1">Item 1</div>
</div>
Flexbox
Browser Support: Flexbox Browser Support
CSS:
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
align-items: center;
justify-content: center;
I think a solid solution for all browsers without using Flexbox - "align-items: center;" is a combination of display: table and vertical-align: middle;.
CSS
.vertically-center
{
display: table;
width: 100%; /* Optional */
height: 100%; /* Optional */
}
.vertically-center > div
{
display: table-cell;
vertical-align: middle;
}
HTML
<div class="vertically-center">
<div>
<div style="border: 1px solid black;">some text</div>
</div>
</div>
‣Demo: https://jsfiddle.net/6m640rpp/
Especially for parent divs with relative (unknown) height, the centering in the unknown solution works great for me. There are some really nice code examples in the article.
It was tested in Chrome, Firefox, Opera, and Internet Explorer.
/* This parent can be any width and height */
.block {
text-align: center;
}
/* The ghost, nudged to maintain perfect centering */
.block:before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
margin-right: -0.25em; /* Adjusts for spacing */
}
/* The element to be centered, can
also be of any width and height */
.centered {
display: inline-block;
vertical-align: middle;
width: 300px;
}
<div style="width: 400px; height: 200px;">
<div class="block" style="height: 90%; width: 100%">
<div class="centered">
<h1>Some text</h1>
<p>Any other text..."</p>
</div>
</div>
</div>
There is a trick I found out recently: You need to use top 50%, and then you do a translateY(-50%).
.outer-div {
position: relative;
height: 150px;
width: 150px;
background-color: red;
}
.centered-div {
position: absolute;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
background-color: white;
}
<div class='outer-div'>
<div class='centered-div'>
Test text
</div>
</div>
A good example of what I'm trying to achieve would be the ticker effect on https://aboutface.com
Based on another example I saw a while back I came up with this. But as you can see, the message crops and you don't see the 2nd message coming into the screen. The scrolling/visible area should span the width of the white box - or 12px from each side with the left/right padding.
https://jsfiddle.net/ho34yvtL/1/
Also, I guess this will be problematic on desktop as you'd need several more duplicate messages. Right now, if I could just display 1 message continuously that'd be great. But ideally I'd like to support multiple.
So basically I want text to scroll continuously across the screen with set spacing between each item. So you see multiple messages at the same time if space allows, unlike the old school marquee tag.
If what I'm trying to achieve isn't possible, is there a preferred method for this, a plugin or will it require complex/custom javascript?
Apply width:100% to .msg. If we want to apply a 12px padding on the left and right, we can use CSS calc() to subtract 24px from 100%.
Additionally, margin-left:50px can be applied to the messages to get that 50px spacing between the two.
The following example preserves the 12px padding in the container whilst maintaining 50px spacing between each item.
body {
background: red;
}
.page-head {
background: white;
box-sizing: border-box;
padding: 0;
position: fixed;
top: 0;
width: 375px;
}
/**
* Ticker
*/
.page-head__ticker {
display: flex;
align-items: center;
justify-content: center;
font-family: "Arial";
font-size: 11px;
font-weight: Bold;
height: 36px;
line-height: 1;
padding: 0 12px;
text-transform: uppercase;
}
.msg {
margin: 0 auto;
white-space: nowrap;
overflow: hidden;
position: absolute;
width:calc(100% - 24px);
}
.msg span {
animation: marquee 6s linear infinite;
display: inline-block;
padding-left: calc(100% - 24px);
margin-left:50px;
}
.msg--two span {
animation-delay:3s;
margin-left:50px;
}
#keyframes marquee {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(-100%, 0);
}
}
<header class="page-head">
<div class="page-head__ticker">
<p class="msg"><span>Free Shipping on orders over $50</span></p>
<p class="msg msg--two"><span>Free Shipping on orders over $50</span></p>
</div>
</header>
One simple way to get a continuous scrolling effect is to have two copies of your messages and scroll with an animation just 50% of the total width. That way it is smooth - all the messages have gone through and it starts again, 'overwriting' the second copy.
Here's a snippet - it has 24px between the messages but of course such styling can be altered to suit what you want.
body {
background: red;
}
.page-head {
background: white;
box-sizing: border-box;
padding: 0;
position: fixed;
top: 0;
width: 375px;
}
/**
* Ticker
*/
.page-head__ticker {
font-family: "Arial";
font-size: 11px;
font-weight: Bold;
height: 36px;
line-height: 1;
padding: 0 12px;
text-transform: uppercase;
overflow: hidden;
}
.msg {
rmargin: 0 auto;
white-space: nowrap;
overflow: hidden;
animation: marquee 6s linear infinite;
display: inline-block;
}
span {
padding-left: 24px;
/* to give a gap between messages */
}
#keyframes marquee {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(-50%, 0);
/* changed from 100% */
}
}
<header class="page-head">
<div class="page-head__ticker">
<p class="msg"><span>Free Shipping on orders over $50</span><span>And here is the second message</span><span>Free Shipping on orders over $50</span><span>And here is the second message</span></p>
</div>
</header>
If your messages are collectively too short to cover the window allocated to the marquee you may want to increase the gap between eg. with a bit of JS.
So here is a simple fiddle (http://jsfiddle.net/t1xywroc/2/) I created to show you the animation I'm trying to replicate (from this website: https://paperpillar.com/).
I'm still fairly new to Javascript/Jquery and have only been doing HTML and CSS for a couple months.
The problem about my animation is that (as far I know) there is no transition from an absolute position to a fixed position, which I believe causes that small jump, right after triggering the animation (or transition if you will). The second problem is, that the content of the ::before element can't be transitioned either. How can I fix these things using jQuery?
I tried to get it work by using mostly CSS but I keep coming across new problems. I guess it's inevitable to use JavaScript, which is what I need help with. I'd really appreciate it.
Note: not a native speaker.
HTML
<div class="section">
<div class="button"></div>
</div>
CSS
.section {
height: 2000px;
width: auto;
}
.button {
position: absolute;
transform: translateX(50%);
right: 50%;
display: inline-block;
color: white;
line-height: 60px;
height: 60px;
width: auto;
padding-left: 25px;
padding-right: 25px;
background-color: blue;
border-radius: 25px;
vertical-align: middle;
top: 15rem;
}
.button::before{
content: 'Button Text';
}
.floating {
padding-left: 0px;
padding-right: 0px;
position: fixed;
right: 15px;
top: calc(100vh - 120px);
transform: none;
height: 80px;
width: 80px;
transition: all 1.5s ease-in-out;
background-color: red !important;
border: none;
border-radius: 50%;
justify-content: center;
text-align: center;
}
.floating::before{
content:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24px' height='24px' fill='white'><path d='M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z' /></svg>");
}
JS
$(document).ready(function() {
$(window).on('scroll', function() {
if ($(window).width() <= 768) {
var scrollTop = $(this).scrollTop();
$('.button').each(function() {
var topDistance = $(this).offset().top;
if ((topDistance - 30) < scrollTop) {
$(this).addClass('floating');
// Haven't put much thought into this part yet
} else if ((topDistance - 30) >= scrollTop){
}
});
}
});
});
A couple of problems have been highlighted in the question: the 'jump' when the transition moves between absolute and fixed and the fact that pseudo elements' content can not be transitioned.
To get round the absolute to fixed jump problem we can set the button to fixed as soon as the transition is to start and then transition. This is possible by introducing CSS animations rather than transitions.
To appear to transition between content we use before pseudo element to hold the initial text (as in the code given) and introduce an after pseudo element that holds the svg. To give the appearance of transitioning between the two we animate opacity.
Note: in the website which is to be emulated the button initially has a white background over the page's white background. This means the change in shape as the initial button fades away is less obvious. With a contrasting blue background the change in shape is much more obvious. That may or may not be the effect required.
Here's a snippet with animations instead of transitions and moving to fixed immediately the animation starts.
$(document).ready(function() {
$(window).on('scroll', function() {
if ($(window).width() <= 2500) {
var scrollTop = $(this).scrollTop();
$('.button').each(function() {
var topDistance = $(this).offset().top;
if ((topDistance - 30) < scrollTop) {
$(this).addClass('floating');
} else if ((topDistance - 100) >= scrollTop){
}
});
}
});
});
.section {
height: 2000px;
width: auto;
position: relative;
}
.button, .button::before, .button::after {
animation-duration: 1.5s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
animation-timing-function: ease-in-out;
position: absolute;
}
.button {
transform: translateX(50%);
right: 50%;
line-height: 60px;
height: 60px;
width: auto;
color: transparent; /* do this to ensure the button has dimensions so it can be clicked */
display: inline-block;
vertical-align: middle;
top: 15rem;
}
.button.floating {
position: fixed;
top: 30px;
animation-name: floatdown;
}
.button::before {
content: 'Button\00a0 Text';
opacity: 1;
color: white;
line-height: 60px;
height: 60px;
width: auto;
padding-left: 25px;
padding-right: 25px;
background-color: blue;
border-radius: 25px;
}
.button::after {
content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24px' height='24px' fill='white'><path d='M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z' /></svg>");
opacity: 0;
padding-left: 0px;
padding-right: 0px;
height: 80px;
width: 80px;
margin-left: -50%;
background-color: red;
border: none;
border-radius: 50%;
justify-content: center;
text-align: center;
}
div.button.floating::before {
animation-name: fadeout;
}
div.button.floating::after {
animation-name: fadein;
}
#keyframes fadeout {
100% {
opacity: 0;
}
}
#keyframes fadein {
100% {
opacity: 1;
}
}
#keyframes floatdown {
100% {
top: calc(100vh - 120px);
right: 95px; /* 80+15px */
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="section">
<div class="button">Button text</div>
</div>
Note also that if you want the downarrow to fill the circle more you could put it as a background-image with size contain rather than as content.
I'd like to have the .container and .box scale in and out from the one I clicked on. The problem I'm running into is when I scale in and out, it scales in and out from the first .box div, not the one I clicked on.
Each .box will contain it's own unique content, so when viewing this in "Artboard" view (Zoomed Out), I want people to be able to see what's contained in that particular .box. When people click on one of the boxes, I want it to scale back to (1) to cover the viewport. And if the person is on the 4th .box and they click "Zoom Out", I want it to zoom out from that particular .box.
Each box will be the size of the viewport, which is how it's set up now.
Does anyone have a solution in CSS only? Or is this something that can be better accomplished in JS? I'm not a JS expert, I'm just getting into it, so I'm curious if there's something I can do in some simple JS.
Please see my codepen:
http://codepen.io/jareko999/pen/eZGLZB
HTML
<div class="bar">
<button class="zoomout" onclick="zoomOut()">Zoom Out</button>
</div>
<div class="container">
<div class="artboard">
<div class="box">
<i class="fa fa-diamond"></i>
</div>
<div class="box">
<i class="fa fa-bolt"></i>
</div>
<div class="box">
<i class="fa fa-flag"></i>
</div>
<div class="box">
<i class="fa fa-flask"></i>
</div>
</div>
</div>
CSS
body {
margin: 0;
padding: 0;
height: 100vh;
width: 100%;
background: #e1e1e1;
overflow-y: hidden;
}
.bar {
position: fixed;
display: flex;
flex-direction: row;
box-sizing: border-box;
bottom: 0;
width: 100%;
height: 80px;
background: white;
padding: 14px 0;
z-index: 1;
}
.zoomout {
-webkit-appearance: none;
border: none;
outline: 0;
width: 100px;
height: 40px;
margin: auto;
background: black;
color: white;
border-radius: 10px;
cursor: pointer;
}
.container {
height: 100vh;
width: 100%;
transition: .2s ease-out;
transform: scale(1);
}
.container-small {
height: 100vh;
width: 100%;
transition: .2s ease-out;
transform: scale(.7);
}
.artboard {
height: 100%;
width: 100%;
display: flex;
display: -webkit-flex;
background: #e1e1e1;
}
.box {
padding-top: 44vh;
box-sizing: border-box;
text-align: center;
flex-shrink: 0;
width: 100%;
height: 100%;
box-shadow: 0 2px 4px #a9a9a9;
background: linear-gradient(to right, #276cd6 , #00a651);
transition: .2s ease-out;
transform: scale(1);
}
.box-small {
padding-top: 44vh;
box-sizing: border-box;
text-align: center;
flex-shrink: 0;
width: 100%;
height: 100%;
box-shadow: 0 2px 4px #a9a9a9;
background: linear-gradient(to right, #276cd6 , #00a651);
transition: .2s ease-out;
transform: scale(.9);
cursor: pointer;
}
.box i {
color: #e1e1e1;
font-size: 3em;
}
.overflow {
overflow: hidden;
}
.remove {
display: none;
}
::-webkit-scrollbar {
width: 12px;
height: 4px;
}
/* Track */
::-webkit-scrollbar-track {
background: white;
-webkit-border-radius: 10px;
border-radius: 10px;
}
/* Handle */
::-webkit-scrollbar-thumb {
-webkit-border-radius: 100px;
border-radius: 100px;
background: #4099ff;
}
JS
$(document).ready(function() {
$('.container').addClass('overflow');
});
function zoomOut() {
$('.bar').addClass('remove');
$('.box').addClass('box-small');
$('.container').removeClass('overflow');
$('.container').addClass('container-small');
}
$('.box').click(function() {
$('.bar').removeClass('remove');
$('.box').removeClass('box-small');
$('.container').addClass('overflow');
$('.container').removeClass('container-small');
});
What you're trying to achieve can be done using a CSS only method.
This method relies on using location hashes (url.com#foobar) and the :target pseudo selector.
The :target pseudo selector allows you to target the element which has the id matching the location hash. For example, imagine you have an element with the id "foobar", the #foobar:target selector will only apply if you have navigated to url.com#foobar. You can create a link with the href attribute pointing #foobar to have a button trigger this pseudo selector.
In your case, you can apply the zoom out styles when the #container location hash is matched, and only show the slide matched by the location hash.
The drawback of this method is that you have to add ids, and add links to actually trigger the :target pseudo class.
My explanation might not be clear, so I put up this demo:
http://codepen.io/ntim/pen/ONxGJd