CSS: "overflow: hidden" alternative that doesn't break 3D transforms - css

I'm trying to make a horizontal section with a parallax effect. In the background there should be an image that scrolls at a different speed than the page.
The problem is: I want the parallax element to be contained in the parent element, so the parent element works kind of like a mask for the child: the child is only visible within the boundries of the parent.
I know that this can be achieved by having the parallax element beetween two elements with backgrounds that are "above" the parallax element and obstruct it, but this method is not applicable for my case.
The obvious idea that comes to mind is to use overflow: hidden on the parent. This however breaks the 3D transforms so there is no parallax left.
How do I achieve the described effect?
Here is a codepen: https://codepen.io/rradarr/full/mdwgard.
I want the red rectangle to not be visible outside the "parallax-container" with the black border.
* {
margin: 0;
}
html, body {
height: 100%
}
main {
position: relative;
width: 100%;
perspective: 1px;
transform-style: preserve-3d;
overflow-y: auto;
overflow-x: hidden;
height: 100vh;
background-color: blue;
}
.static {
min-height: 800px;
}
.parallax-container {
border: solid black 3px;
height: 600px;
width: 100%;
transform-style: preserve-3d;
position: relative;
}
.parallax-child {
position: relative;
width: 100%;
height: 100%;
transform: translateZ(-2px) scale(2.01);
z-index: -1;
}
#img-or-whatever {
height: 900px;
width: 100%;
background-color: red;
position: relative;
z-index: -1;
}
<main>
<div class="static"></div>
<div class="parallax-container">
<div class="parallax-child">
<div id="img-or-whatever"></div>
</div>
</div>
<div class="static"></div>
</main>

As far as I know you can't achieve the described effect with translateZ.
This is because according to this article about CSS 3D
...giving overflow any value other than visible effectively forces the value of transform-style to flat, even when we have explicitly set it to preserve-3d.
The only alternative for overflow hidden is to put something "above" the parallax element as far as I know (which you said you want to avoid).
If there is really no option to put something "above" the parallax element you could try to do something similar with js (something like this for example). This is not ideal since it will imply a lot of calculations and variables and might take some time to accomplish exactly what you want (and you loose the 3D inside the container since you need overflow: hidden anyway).
If you really need the 3d inside there you could create a more complex solution with javascript that skips overflow: hidden as well. But I'd try to avoid that if is not mandatory (I'd rather add an absolute element over the overflow: hidden container where 3D is enabled. And give the absolute container transparent background if you still need 3D in that section).
Usually I would also advise to try to avoid .js for this kind of stuff (if possible) but I don't think you have a lot of options here.

You could try the :not() pseudo clss, but I don't know what you would pass into the parentheses that would be similar to not in the black square.

Related

How to stack elements along the z axis without using absolute positioning?

Let's say that I want to have layout that doesn't scroll (meaning width=100, height=100) with one container and
two child elements. Now, when you don't apply any of the positioning context, all the elements follow natural flow of the document which means they stack below each other. How do I achieve positioning along the z-axis (stack them in front of each other) without using absolute positioning?
To be precise, here is fiddle:
https://jsfiddle.net/Rokke/wb10ozme/7/
<div class="wrapper">
<div class="child-01">Child-01</div>
<div class="child-02">Child-02</div>
</div>
html {
width: 100%;
height: 100%;
overflow: hidden;
}
.wrapper {
width: 100%;
height: 100%;
background-color: black;
}
.child-01 {
width: 350px;
height: 450px;
background-color: red;
}
.child-02 {
width: 650px;
height: 350px;
background-color: blue;
}
What I want to achieve: child-01 centered horizontally on the page along the bottom edge of the screen, child-02 centered horizontally as well but in front of child-01. I accomplished this by using absolute positioning but then when you open up the developer tools it moves (because of the bottom: 0 property). If I was to use position relative I would have to use negative margin to bring them in front of each other. Does anyone have some idea how this can be achieved in a much better way?

How to stop mobile safari from setting fixed positions to absolute on input focus?

Disclaimer - I understand there exists questions around fixed elements in safari, and fixed elements weren't supported, but now are and so forth. However I can't find a question that addresses this exact question.
Given the simplest of fixed sidebars, something like:
.sidebar {
position: fixed;
top: 10px;
right: 10px;
}
And a relatively long page, with input elements.
When an input element is focused, any fixed element becomes absolute - I understand the why, safari is trying to declutter the viewport - thats fine, but not always appropriate. I ask that I get to choose the best experience for the user (i know best naturally).
So the Question..
Is there any way to leave fixed elements as fixed even when input elements are focused?
I have attempted to do a bit of $(window).on('scroll', magic and position elements manually on scroll, but its quite jittery on the ipad.
Safari has supported position: fixed since at least version 9.2, but if you're seeing difficult issues, you can fully create the fixed position effect by making the document element and body full screen and then using absolute positioning. Scrolling then occurs in some main container element rather than the body. Your "fixed" elements can exist anywhere in the markup using this method.
jsfiddle here
html,
body,
.mainContainer {
height: 100%;
width: 100%;
overflow: hidden;
margin: 0;
}
.mainContainer {
overflow: auto;
}
.fixed {
position: absolute;
bottom: 20px;
left: 20px;
}
In order to achieve the effect you desire you need to change your approach to the layout. Instead of positioning the sidebar with position:fixed you need to use position:absolute within a position:relative container that is set to the height of the viewport within that position:relative container you need another div that uses overflow-y: scroll and -webkit-overflow-scrolling : touch
Caveat: I generally avoid using position fixed on tablet & mobile if possible although the browser support is there, in my experience it'll be janky and javascript solutions leave a lot to be desired, my first response would be to challenge the pattern with the designer. If I'm given designs that include a position fixed element when there are input elements, I'm more likely to seek a design solution than a development one as the focus issues you're describing are difficult to circumvent and maintain a quality user experience.
THE MARKUP:
<div class="outer">
<div class="sidebar">
<ul>
<li>Dummy list nav or something</li>
</ul>
</div>
<div class="container">
<input type="text" />
<!-- I added 10000 inputs here as a demo -->
</div>
</div>
THE CSS:
html,body{
-webkit-overflow-scrolling : touch !important;
overflow: auto !important;
height: 100% !important;
}
.outer {
position: relative;
overflow: hidden;
/* I'm using Viewport Units here for ease, but I would more likely check the height of the viewport with javascript as it has better support*/
height: 100vh;
}
.sidebar {
position: absolute;
top: 10px;
right: 10px;
/*added bg colour for demo */
background: blue;
}
.container {
height: 100vh;
overflow-y: scroll;
-webkit-overflow-scrolling: touch
}
input {
display: block;
}
Here's a CodePen for you to open in your simulator (presentation view):
https://codepen.io/NeilWkz/full/WxqqXj/
Here's the editor view for the code:
https://codepen.io/NeilWkz/pen/WxqqXj

How to create an overlay that doesn't overflow its parent container?

I have 2 columns separated by 2 container.
In the first column I have set an element <div class="overlay"></div>
that should cover and overlay ONLY the first column.
I set the following css property on the class overlay.
.overlay {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(255,255,255,0.8);
}
However, it doesn't just cover only the first column. It also cover the other second column.
I don't wanna set a fix width and fix height because I want to overlay the whole container. And I might run into issues soon if I do fix width.
Here is the sample fiddle of what I have so far..
Try adding this CSS
.container-1{
overflow: hidden;
position: relative;
}
Demo
I am not sure what you are trying to do with the overlay. But you can try this code:
.overlay {
position: relative;
width: 100%;
height: 100%;
background-color: rgba(255,255,255,0.8);
}
The relative position will force it to stay within the container. The problem is that bc your overlay has nothing in it, it won't show up.
This is what I done to make it show up -> https://jsfiddle.net/908zodam/ (i just added a blank character in the overlay.)

CSS resize handle "z-index"

I'm trying to do a resizable canvas element using CSS resize. The setup looks like this:
HTML:
<div class="canvas-wrapper">
<canvas></canvas>
</div>
CSS:
.canvas-wrapper {
position: relative;
overflow: hidden;
resize: horizontal;
}
.canvas-wrapper canvas {
width: 100%;
height: auto;
}
It works just fine but the resize handle is always hidden by the canvas. I surely could add an additional child element with the resize property to the wrapper and place it above the canvas but this seems rather inelegant.
Now is there any way to influence the "z-index" of the resize handle?
I've already seen this question but they do a workaround there, too.
Edit: It seems that the handle remains usable in some browsers even if its hidden by the canvas (try this). Probably the spec isn't very accurate on this behaviour. Does anyone have further information about this?
i changed it a bit in this i think this is what you were trying to accomplish
http://jsfiddle.net/aidan2129/U7J9k/
.canvas-wrapper {
position: absolute;
overflow: hidden;
resize: horizontal;
}
.canvas-wrapper2 {
position: relative;
overflow: hidden;
resize: horizontal;
}
.canvas-wrapper canvas {
width: 100%;
height: auto;
background-color:blue;
}
.canvas-wrapper2 canvas {
width: 100%;
height: auto;
background-color:red;
}
It seems to work fine i have just set the position to absolute so it does not take the full length of the page but if you resize the result canvas element to the right you will see the blue canvas appear behind the red one.
Hope this helps
Since it seems there is no solution without a little workaround I finally used the pointer-events: none property mentioned here. This enables the resize handler (at least for me in Firefox and Chrome) no matter if it is behind the canvas or not.
For visual feedback I used a pseudo-element. See the updated fiddle for how it looks like.

Absolute positioned child div expands to fit the parent?

Is there anyway for an absolute positioned child to expand to fill its relative positioned parent? (The height of parent is not fixed)
Here is what i did and it is working fine with Firefox and IE7 but not IE6. :(
<div id="parent">
<div id="child1"></div>
</div>
#parent { position: relative; width: 200px; height:100%; background:red }
#child1 { position: absolute; top: 0; left: 200px; height: 100%; background:blue }
That's easy. The trick is setting top: 0px and bottom: 0px at the same time
Here's the working code
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}
#parent {
display: block;
background-color: #ff0;
border: 1px solid #f00;
position: relative;
width: 200px;
height: 100%;
}
#child1 {
background-color: #f00;
display: block;
border: 1px solid #ff0;
position: absolute;
left: 200px;
top: 0px;
bottom: 0px;
}
Check out a working example here http://jsfiddle.net/Qexhh/
If I remember correctly there is a bug with how IE6 handles div height. It will only create the div to the height needed to contain the content within it when height is set to 100%. I would recommend two approaches:
Don't worry about supporting IE6 as it is a dead browser anyway
If that doesn't work, use something like jQuery to get the height of the parent div and then set the child div to that height.
fake it by setting the backgrounds to be the same colour so no-one notices the difference
You can achieve this with setting both the top and bottom attributes of the child.
See how this is done
At the bottom of that article, there is a link to Dean Edwards' IE7 (and IE8) js library that you should include for IE6 visitors. It is a JS library that actually MAKES IE6 behave like IE7 (or 8) when you include it. Sweet!
Dean Edwars' IE7 and 8 JS libraries
As far as I know, there is no way of expanding a parent element around an absolutely positioned child element. By making the child element absolutely positioned your are removing it from the regular flow of page items.
I recently built a 2-column website where the right column was absolutely positioned but the left column was not. If the left column had less content and a smaller height than the right column, the page would cut off the right column since it was absolutely positioned.
In order to resolve this, I had to determine if the height of the right column was greater than the height of the left column and if so set the height of the parent div height to the greater of the two.
Here is my jQuery solution. I'm not much of a coder so feel free to tweak this:
jQuery(function(){
var rightColHeight = jQuery('div.right_column').height();
var leftColHeight = jQuery('div.left_column').height();
if (rightColHeight > leftColHeight){
jQuery('.content_wrap').height(rightColHeight+'px');
}
});

Resources