I want to make divs which got backgrounds that have this 3d-effect while scrolling, that one can achieve with translateZ. In the end it should look like cutouts or windows and through them you can see the (background-)images.
edit: So, if you scroll through the page you can see those boxes/cutouts but the images inside them are moving slower while scrolling to create the effect that they are further away. end of edit
What I have in mind is to have one div for the cutout and then another div inside it for the background. So, i set it up and it didn't work. It turns out that the overflow: hidden; of the outer div somehow blocks the transform: translateZ(-5px) scale(1.05); of its child.
Here is what I have got so far:
body {
perspective: 100px;
transform-style: preserve-3d;
overflow-x: hidden;
overflow-y: scroll;
}
#artwork, #photos {
width: 800px;
padding: 0 50px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
}
.pic {
/*position: relative;*/
width: 200px;
height: 100px;
display: inline-block;
background: #aaa;
border-radius: 10px;
box-shadow: inset 0 10px 30px rgba(0,0,0,.3);
}
#artwork > * {
overflow: hidden;
}
.pic div {
position: absolute;
width: 200px;
height: 110px;
background: #660; /*couldn't put an image here*/
background-size: cover;
transform: translateZ(-5px) scale(1.05);
}
<section id="artwork">
<div class="pic"><div></div></div>
<div class="pic"><div></div></div>
<div class="pic"><div></div></div>
</section>
P.S.: I don't want to achieve the effect via JavaScript because it's not working smoothly on most computers.
edit n°2: my approaches so far:
- making extra tick borders to cover overlapping parts of the image divs; instead of using overflow: hidden >> parts are sometimes still overlapping on some screen sizes & it takes a lot of space
- creating a clip-path to use as overflow: hidden >> clip-paths also break the translateZ
- playing around with display and position on both outer and inner div >> only solutions without cutout
- Ztranslating the parent of the outer div further away and then bringing the outer div close again >> still blocked by the overflow: hidden;
I found a workaround, although it's a compromise because the border radius isn't working. I added thick borders in the background color to the outer divs and set the z-index of the inner divs to something negative.
body {
height: 200px;
perspective: 100px;
transform-style: preserve-3d;
overflow-x: hidden;
overflow-y: scroll;
}
#artwork {
width: 800px
padding: 0 50px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
}
.pic {
width: 200px;
height: 100px;
margin: -40px;
display: inline-block;
background: transparent;
border: 40px solid hsl(30, 50%, 90%);
box-shadow: inset 0 10px 30px rgba(0,0,0,.3);
}
.pic div {
position: absolute;
width: 200px;
height: 110px;
background: linear-gradient(135deg, rgba(240,183,161,1) 0%,rgba(140,51,16,1) 50%,rgba(117,34,1,1) 51%,rgba(191,110,78,1) 100%);
transform: translateZ(-5px) scale(1.05) translateY(-1vw);
z-index: -20;
}
#artwork div:nth-child(2) div, #photos div:nth-child(2) div {transform: translateZ(-5px) scale(1.05) translateX(-1.5vw) translateY(-1vw);}
#artwork div:nth-child(4) div, #photos div:nth-child(4) div {transform: translateZ(-5px) scale(1.05) translateX(1.5vw) translateY(-1vw);}
<br><br><br><br><br><br><br>
<section id="artwork">
<div class="pic"><div></div></div>
<div class="pic"><div></div></div>
<div class="pic"><div></div></div>
</section>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
that code snippet doesn't work here for some reason. For me however it works in the browser. It would be nice if someone could suggest another possible solution as this one works with only some screen sizes.
Related
First, English is not my home language, so i apologize for any mistakes or typos.
I am trying to build an isometric grid for one of my personal projects, however i encounter a problem.
(for all the following screenshots, i removed the rotation of the grid to ease comprehension)
The setting:
My grid is generated using flex and html. I will position some elements at selected squares using links with a background-image
and here is an example of the html
<div class="town-map-container" style="background-color: green;">
...
<div class="town-row" style="order: X;">
...
<div class="town-square" style="order: Y;">
<a class="building-img" href="#available-modal-X-Y" style="background-image:url("");"></a>
</div>
...
</div>
...
</div>
and the related css:
.town-map-container {
height: 1920px;
width: 1920px;
//transform: rotateX(60deg) rotateY(0deg) rotateZ(-45deg);
.town-row {
display: flex;
flex-direction: row;
width: 100%;
height: 5%;
.town-square {
height: 100%;
width: 5%;
border: 1px ridge black;
.building-img {
display: inline-block;
min-height: 100%;
width: 100%;
position: relative;
left: 0;
bottom: 0;
//transform: rotateX(0deg) rotateY(0deg) rotateZ(45deg);
background-size: 100% 100%;
background-repeat: no-repeat;
}
.building-img:hover {
border-color: blue;
box-shadow: 0 0 10px blue;
}
}
}
}
And now to the question:
I would like for the child element to overflow from the right and the top of the square.
however, while increasing the width of the element overflow it from the right, increasing his height overflows it from the bottom.
(here I increased both height and width to 120%)
I tried a few options (position: relative; botom: 0; left: 0;, ...) but i am first a backend developer and it seems I cannot think about (or google) a solution, any ideas ?
Thanks in advance.
Here is a short codepen of a simple css animation that I'm struggling to work with. Code also below:
.navscroll {
width: 100%;
height: 100px;
padding: 5px;
overflow: hidden;
position: relative;
background-color: red;
}
.navscroll div {
position: relative;
width: 200px;
height: 100%;
line-height: 50px;
text-align: center;
background-color: blue;
opacity: 1;
border-radius: 5px;
transform: translateX(100%);
animation: navscroll 15s linear infinite;
}
#keyframes navscroll {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(-100%);
}
}
<div class="navscroll">
<div>Why arent these</div>
<div>Side by side</div>
<div>or sliding across the WHOLE navbar</div>
</div>
Its supposed to be a scrolling navbar of divs, but I'm having two issues:
The inner divs are stacking vertically, not horizontally...
The inner divs are scrolling across only a small percentage of the nav bar / outer div...
Ideally, if there were many divs in the navscroll div, only 5-6 of them would display anytime on the screen, although the navbar would always be scrolling and those other divs would make their way onto the screen eventually. (similar to stock tickers ticking across the top of the TV screen). Any help with this is appreciated, thanks!!
div is a block level element (means it has display: block; by default). These create a line break before and after themselves. Use display: inline-block; and make sure they align properly using vertical-align: middle;.
2nd problem: translateX(100%) here the percentage does not refer to the parent element, but to the div being animated.
.navscroll {
width: 100%;
height: 100px;
padding: 5px;
overflow: hidden;
position: relative;
background-color: red;
white-space: nowrap;
}
.navscroll div {
position: relative;
width: 200px;
height: 100%;
line-height: 50px;
text-align: center;
background-color: blue;
opacity: 1;
border-radius: 5px;
transform: translateX(100%);
animation: navscroll 15s linear infinite;
/* this does the magic: */
display: inline-block;
vertical-align: middle;
}
#keyframes navscroll {
0% {
left: 100%;
}
100% {
left: -100%;
}
}
<div class="navscroll">
<div>Why arent these</div>
<div>Side by side</div>
<div>or sliding across the WHOLE navbar</div>
</div>
As per your question about how to create a snippet here:
The inner divs are stacking vertically because the default styling for a div is display: block. Adding the styles display: inline-block; vertical-align: top; to your .navscroll div rules will set them side by side, aligned to their top edges.
The animation is starting in the middle, and not all the way to the right like you intend because of how transform: translate() works. transform refers to the object being transformed, not its parent. So, translating something 100% of it refers to the width of the object. Try animating the position, something like this instead:
#keyframes navscroll {
0% {
left: 100%;
}
100% {
left: -600px;
}
}
EDIT: Also, remove the initial transform: translateX(100%); and you can simply animate the left position to -600px (3x the width of the each block).
This is what i am trying to achive
i have :
#image1 {
position: absolute;
bottom: 0px;
align-self: auto;
background-color: #dc022e;
width: 340px;
height: 100px;
border-radius: 50% / 100%;
border-bottom-left-radius: 0;
/*transform: rotate(10deg);*/
border-bottom-right-radius: 0;
opacity: 0.8;
}
#image2 img {
width: 80%;
}
<div>
<div id="image2">
<img src="http://t1.gstatic.com/images?q=tbn:ANd9GcThtVuIQ7CBYssbdwtzZjVLI_uw09SeLmyrxaRQEngnQAked5ZB">
</div>
<div id="image1"></div>
</div>
Finally I don't know how to make it rotated and with the margins cut like in the picture
A Quick example of this would use a pseudo element and have the image set in the background.
div {
position: relative;
height: 300px;
width: 500px;
background: url(http://lorempixel.com/500/300);/*image path*/
overflow: hidden;/*hides the rest of the circle*/
}
div:before {
content: "";
position: absolute; /*positions with reference to div*/
top: 100%;
left: 50%;
width: 0;/*define value if you didn't want hover*/
height: 0;
border-radius: 50%;
background: tomato;/*could be rgba value (you can remove opacity then)*/
opacity: 0.5;
transform: translate(-50%, -50%);/*ensures it is in center of image*/
transition: all 0.4s;
}
/*Demo Only*/
div:hover:before {/*place this in your pseudo declaration to remove the hover*/
height: 100%;
width: 150%;/*this makes the shape wider than square*/
transform: translate(-50%, -50%) rotate(5deg);/*ensures it is in center of image + rotates*/
}
div {/*This stuff is for the text*/
font-size: 40px;
line-height: 300px;
text-align: center;
}
<div>HOVER ME</div>
Instead of nested elements, you can just use a pseudo element. This is placed at the bottom of the container div. For this to work, you need position:relative and overflow:hidden on the container div. Also, pseudo elements always need the content declaration.
To modify the border radius, you just play around with left | width | height of the pseudo element. You don't need any rotation.
Instead of hex color and opacity you can as well use the "new" color space rgba(r,g,b,a) where a is the opacity value.
For the passepartout you simply use the border declaration.
#image2{
position:relative;
border:10px solid #888;
overflow:hidden;
box-shadow:0 0 4px #aaa;
}
#image2::after {
content:"";
display:block;
position: absolute;
bottom: 0;left:-10%;
background-color: #dc022e;
width: 120%;
height: 60%;
border-radius: 100% 100% 0 0;
opacity: 0.8;
}
#image2 img {
width: 100%;
display:block;
position:relative;
}
<div id="image2">
<img src="http://t1.gstatic.com/images?q=tbn:ANd9GcThtVuIQ7CBYssbdwtzZjVLI_uw09SeLmyrxaRQEngnQAked5ZB">
</div>
You can just use position: absolute for your image and position: relative for your overlay, adjusting the top position and width according to your needs. Here's a Fiddle. Hope this helps!
Edit: Here's an updated version of the Fiddle demonstrating border and overflow properties on the img container. As CBroe mentioned, rotating a circle is probably not a good use of your time in this case. Also, I definitely agree that using a pseudo element is a much cleaner approach than nesting images.
I'm trying to center a div with an unknown height.
I can't find a solution that allows scroll to the top of the div when the viewport height is less than the div height.
HTML
<div>
<p>This will be hidden when <br />
window_height < div_width</p>
<br />
<br />
<br />
How to make it scroll to the top?
</div>
CSS
body {
background: grey;
}
p{
background: green;
}
div {
position: absolute;
left: 50%;
top: 50%;
box-sizing: border-box;
transform: translate(-50%, -50%);
max-width: 500px;
width:100%;
height: 700px; /* Unknown*/
padding: 20px;
background: red;
color: white;
text-align: center;
}
http://codepen.io/Koopa/pen/GpypdX
Thanks
The reason you can't scroll to the top of the div is because the transform property with negative values positions the div off-screen on smaller screens.
In this demo transform is disabled:
http://codepen.io/anon/pen/wKpMyM
Also, when you apply absolute positioning to an element you take it out of the normal flow of the document. This means it is ignored by its container. Hence, the body and html element have zero height.
In this demo the body has a green border (which is totally collapsed):
http://codepen.io/anon/pen/RWxrod
To make your layout work, you can give the body a minimum height (so it can expand along with the div) and, instead of centering with absolute positioning, use a flexbox.
CSS
html { height: 100%; } /* necessary for percentage heights to work */
body {
background: grey;
border: 10px solid green; /* for demo purposes */
min-height: 100%; /* allow body to expand with children */
display: flex; /* establish flex container */
justify-content: center; /* center div horizontally, in this case */
align-items: center; /* center div vertically, in this case */
}
p {
background: green;
}
div {
/* REMOVE
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%); */
box-sizing: border-box;
max-width: 500px;
width:100%;
height: 700px; /* Unknown*/
padding: 20px;
background: red;
color: white;
text-align: center;
}
DEMO: http://codepen.io/anon/pen/OyzMvV
Note that flexbox is supported by all major browsers, except IE 8 & 9.
Setup
I have three divs using CSS3 translations in all directions within a container div that is itself within an outer, fullscreen div. The outermost div, the full screen one, has perspective set on it.
HTML
<div class='outer'>
<div class='container ofhidden'>
<div class='item' id='item1'></div>
<div class='item' id='item2'></div>
<div class='item' id='item3'></div>
</div>
</div>
CSS
.outer {
perspective: 1000;
width: 100%;
height: 100%;
position: absolute;
overflow: hidden;
}
.outer .container {
background-color: grey;
width: 130%;
height: 100%;
padding: 1em;
}
.outer .container.ofhidden {
overflow: hidden;
}
.outer .container .item {
border: 1px solid black;
width: 50px;
height: 50px;
}
.outer .container .item#item1 {
background-color: green;
transform: translate3d(10px, 10px, -10px);
}
.outer .container .item#item2 {
background-color: goldenrod;
transform: translate3d(10px, 10px, 0);
}
.outer .container .item#item3 {
background-color: red;
transform: translate3d(10px, 10px, 10px);
}
Problem
The div that contains the translated elements has overflow: hidden; set on it which disables or ignores the translation in the Z direction while not effecting the other directions.
Demo
Please see this pen http://codepen.io/aaron/pen/Ihrxj for the code and a button which toggles overflow: hidden; to demonstrate the effect.
For those not familiar with HAML, SCSS/Compass, or CoffeeScript, you can click on the name of the preprocessor next to HTML, CSS, and JS to see the generated code in the codepen.
I don't know why this is happening, but i can suggest a couple of workarounds.
An obvious solution is to set overflow: hidden; (if you really need it) on items (either with .item or .container > *, instead of applying it to the container.
Another option is to position items absolutely. It's not very handy but it might work out for your layout (you can position items absolutely relatively to the container).
In both cases transform3d won't be disabled/ignored.