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.
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.
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.
I'n using translateY() to pull an element up to overlap an element above it.
.element {
transform: translateY(-50%);
}
It leaves space to the bottom. Is there any way to pull up any elements below it?
https://codepen.io/anon/pen/OBYRMe
In the example you can see it overlaps the element on top which is what I want but leaves space on the bottom. I am trying to achieve this without modifying other elements (e.g. use transform on elements on the bottom as well)
Note: using margin -50% does not work because it doesn't bring up the element 50% relative to the element's height. Only transform calculates the height to my knowledge.
You can apply transform on elements on bottom using the following css.I hope this is what you are looking for
.element ~ div {
transform: translateY(-50%);
}
You can use a negative big value in margin-bottom to pull the other elements:
body {
text-align: center;
}
.test, .element {
width: 80%;
padding: 60px 0;
background: green;
display: inline-block;
}
.element {
width: 30%;
background: yellow;
display: inline-block;
transform: translateY(-50%);
margin-bottom:-100vh;
}
<div class="test"></div>
<div class="element">:-)</div>
<div class="test"></div>
<br><br>
<div class="test"></div>
Use margin-top: -50%; instead. Happy coding
You can use the box-shadow properties to solve the your problem otherwise you can use the flex-box or position etc. anyway I gave solution but I'm not sure you want this things or not:)
body {
text-align: center;
}
.test, .element {
width: 80%;
padding: 60px 0;
background: green;
display: inline-block;
}
.element {
width: 30%;
background: yellow;
display: inline-block;
transform: translateY(-50%);
box-shadow:0px 100px yellow;
}
<div class="test"></div>
<div class="element">:-)</div>
<div class="test"></div>
I run into this issue a lot where I need the width of an inner container (like a wrapper with a set width of 960px) to span a width of 100%, and I'm unable to touch the html so it must all be done with css.
I know I can position: absolute; that guy to break him out of the wrapper... but is there another... better way?
Here is a JsFiddle link to help make it a little clearer:
http://jsfiddle.net/KRyF6/
<!-- html -->
<div id="container">
<div id="inner-container"></div>
</div>
<!-- CSS -->
#container {
width: 500px;
height: 500px;
background: gray;
margin: auto;
}
/* here's the container that I want to be 100% */
#inner-container {
width: 100%; /* :( */
height: 100px;
background: black;
}
Edit:
Here is a jsFiddle with my absolute position version... what I'd like to know is if this can be done without absolute positioning
http://jsfiddle.net/KRyF6/3/
<div id="container2">
<div id="inner-container2">
</div>
#container2 {
width: 500px;
height: 500px;
background: gray;
margin: auto;
clear: both;
margin-top: 20px;
}
#inner-container2 {
background: black;
width: 100%;
height: 100px;
position: absolute;
left: 0;
}
Well there is another way of doing this.
Body -> Container -> child
Now this way as the title suggest is passing its width to the container and from the container to it's child. This way the child can get the total width of the body.
Explanation
The only problem you are facing here is that an static width will not keep the <body> width in mind(aka the viewport). So you have to use percent values for the width so it will be based on the <body>:
#container {
/*width: 500px;*/
width: 70%;
height: 500px;
background: gray;
margin: auto;
}
Now the child knows that the width of its parent(#container) is 70% of the total body.
However a width of 100% will only get 70% of the <body> width. Instead you need 100% + the 30% of the 70%. And 30% of 70% is like 42%( 35% would be 50%).
Now we got the 100% of the <body>. Now you can let it look like it is outside the container width a negative margin. To center it you want it to be minus half of the 42%(=30% of the body) which you just calculated:
#inner-container {
/*width: 100%; /* :( */
width: 142%;
margin-left: -21%;
height: 100px;
background: black;
}
jsFiddle
However, is this easy to use?
Well it is an answer to your question. It is possible without using position: absolute.
Would position absolute be easier?
Definitely:
#inner-container {
width: 100%; /* :( */
height: 100px;
background: black;
position: absolute;
left: 0;
}
Only two lines of code without any calculates :)
jsFiddle
I'm gonna go out on a limb and say 'no' on this one.
There's no way of making the inner div span the entire width of the page without breaking it out of the document flow, i.e. absolutely positioning it.
I think it could be done only with absolute position:
#inner-container {
width: 100%; /* :( */
height: 100px;
background: black;
left: 0;
position: absolute;
}
Fiddle
Actually, this can be done with calc() in conjunction with viewport units vw
FIDDLE - Working in iE10+
#inner-container {
height: 100px;
background: black;
width: 100vw;
margin-left: calc(250px - 50vw);
}
Actually, according to the spec (see example 14) - this should work (that is - in all browsers), but for now there's a bug where calc doesn't work with viewport units.
Alternatively you could do this:
#inner-container {
height: 100px;
background: black;
margin-right: calc(250px - 50vw);
margin-left: calc(250px - 50vw);
}
-- this way - in IE it will look as required, and on other browsers it will look centered as you have it.
FIDDLE
Normally, you center images with display: block; margin: auto, but if the image is larger than the container, it overflows to the right. How do I make it overflow to the both sides equally? The width of the container is fixed and known. The width of the image is unknown.
A pure css solution
Requiring one extra wrapper (tested in FireFox, IE8, IE7):
Improved Answer
There was a problem with the original answer (below). If the image is larger than the container that outer is centered on with it's auto margins, then it truncates the image on the left and creates excessive space on the right, as this fiddle shows.
We can resolve that by floating inner right and then centering from the right. This still truncates the img off the page to the left, but it does so by explicitly pushing it that way and then centers back off of that, the combination of which is what prevents the extra horizontal scroll on the right. Now we only get as much right scroll as we need in order to see the right part of the image.
Fiddle Example (Borders in fiddle are for demo only.)
Essential CSS
div.outer {
width: 300px; /* some width amount needed */
margin: 0 auto;
overflow: visible;
}
div.inner {
position:relative;
float: right; /* this was added and display removed */
right: 50%;
}
div.inner img {
position: relative;
right:-50%; /* this was changed from "left" in original */
}
If you desire no right scroll at all for wide images
Then using the above, also set whatever element wraps outer (like body or a third wrapper) to have overflow: hidden.
Original Idea (for History)
Fiddle Example (Borders in fiddle are for demo only.)
HTML
<div class="outer">
<div class="inner">
<img src="/yourimage.png">
</div>
</div>
CSS
div.outer {
width: 300px; /* some width amount needed */
margin: 0 auto;
overflow: visible;
}
div.inner {
display: inline-block;
position:relative;
right: -50%;
}
div.inner img {
position: relative;
left:-50%;
}
Here's a 2 line CSS solution (a couple more lines might be required for cross-browser support):
img {
margin-left: 50%;
transform: translateX(-50%);
}
HTML
ā<div class="image-container">
<img src="http://www.google.com/images/logo.gif" height="100" />
</div>ā
CSS
.image-container {
width: 150px;
border: solid 1px red;
margin:100px;
}
.image-container img {
border: solid 1px green;
}
jQuery
$(".image-container>img").each(function(i, img) {
$(img).css({
position: "relative",
left: ($(img).parent().width() - $(img).width()) / 2
});
});
ā
See it on jsFiddle: http://jsfiddle.net/4eYX9/30/
Alternative pure CSS solution is to use transform attribute:
HTML:
<div class="outer">
<img class="image" src="http://www.gstatic.com/webp/gallery/4.jpg" />
</div>
CSS:
.outer {
position: relative;
width: 100px;
border: 1px solid black;
height: 150px;
margin-left: 100px; /* for demo */
/* overflow: hidden; */
}
img.image {
width: 200px;
opacity: 0.7;
position: absolute;
left: 50%;
transform: translateX(-50%);
-webkit-transform: translateX(-50%);
}
Fiddle
Just to add a overflow:hidden to parent div to hide the extra area of the image.
Your best bet is to set it as background image of the container instead.
#container {
background: url('url/to/image.gif') no-repeat center top;
}
In fact there is a simpler pure css/html way (without large horizontal scroll) :
Html :
<div class="outer">
<img src="/my/sample/image.jpg">
</div>
Css :
If you don't want to see image overflow
div.outer img {
position: absolute;
left: -50%;
z-index:-1;
}
div.outer {
overflow: hidden;
position: relative;
height: 200px;
}
With image overflow visible
div.outer img {
position: absolute;
left: -50%;
z-index:-1;
}
div.outer {
overflow: visible;
position: relative;
height: 200px;
}
body, html {
overflow-x:hidden;
}
A background solution with image overflow visible :
Html :
<div class="outer">
<div class="inner"></div>
</div>
Css :
div.outer {
width: 100%;
height: 200px;
}
div.inner {
background: url('/assets/layout/bg.jpg') center no-repeat;
position: absolute;
left: 0;
width: 100%;
height: inherit;
}
assuming outer is in a width specified container.
I see this is an old post, so maybe everybody knows this by now, but I needed help for this and I solved it using flex:
.parent {
display: flex;
/* give it the width and height you like */
}
.parent img {
min-width: 100%;
min-height: 100%;
object-fit: cover;
}
I can only think of a Javascript solution since what you need to do is relatively position the image a negative amount to the left of its container:
jQuery
$(document).ready(function(){
var theImg = $('#container img');
var theContainer = $('#container');
if(theImg.width() > theContainer.width()){
theImg.css({
position: 'relative',
left: (theContainer.width() - theImg.width()) / 2
})
}
})
I found this to be a more elegant solution, without flex, similar to something above, but more generalized (applies on both vertical and horizontal):
.wrapper {
overflow: hidden;
}
.wrapper img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* height: 100%; */ /* optional */
}
I don't think there is a pure CSS solution (Except for the next answer :)). However with Javascript it would be just a matter of finding the width of the image, subtracting the container width, dividing by two and you have how far to the left of the container you need.