I'm rotating a div in 3D space. It's pretty simple:
<div class="holder">
<div class="box">
<p>This is some text.</p>
</div>
</div>
.box {
background: orange;
color: #fff;
font-size: 6em;
transform: rotateY(60deg);
padding: 20px;
position: absolute;
}
.holder {
perspective: 300px;
max-width: 600px;
margin: 0 auto;
}
I notice that in IE11 and Firefox, if the transform makes the shape run out of the viewport, it will display scrollbars. This happens even if the item is out of the flow, by setting position: absolute. In Chrome, no scrollbars are displayed.
My understanding was that 3D transforms don't take up any additional space than the non-3D version of the item, so I'm not sure whey scrollbars are appearing in some browsers. Is this the correct behavior?
Yes, this is correct behavior as per spec: http://dev.w3.org/csswg/css-transforms-1/#transform-rendering
For elements whose layout is governed by the CSS box model, the transform property does not affect the flow of the content surrounding the transformed element. However, the extent of the overflow area takes into account transformed elements. This behavior is similar to what happens when elements are offset via relative positioning. Therefore, if the value of the overflow property is scroll or auto, scrollbars will appear as needed to see content that is transformed outside the visible area.
Common workaround for this kind of behavior would be setting overflow: hidden on html element and then reseting it to auto or scroll lower in the DOM, based on your needs.
Related
I have an angular page, home, which is comprised of 2 components and a router-outlet
<div class="home-container">
<header></header>
<sub-header></sub-header>
<router-outlet></router-outlet>
</div>
I want the home-container above to always be, at a minimum, full screen height. The header should show, then the sub-header, then the contents of the router-outlet should always fill up at least the rest of the screen (or more if there's more content of course).
Normally this is easy but it seems the router-outlet is messing it up. Example can be seen http://plnkr.co/edit/56k9ZabLAGujBoX8Lsas , hit run and then click the "Heroes" link to route. In this example I don't want the Heroes div to be taller than the screen, and don't understand why it is.
My styles to accomplish this are. (assume router-outlet is on 'my-page')
html, body {
height: 100%;
}
.home-container {
height: 100%;
}
.my-page {
height: 100%;
}
My expectation here obviously is that home-container is full screen, shows header, shows sub-header, and that my-page then fills in at a minimum the rest of the vertical height.
What is actually happening though, is that there's a scroll bar with available height that appears equal to my header and sub-header.
This plnkr http://plnkr.co/edit/56k9ZabLAGujBoX8Lsas illustrates exactly my meaning. If you click Run and then the link for "Heroes" you will see the router-outlet contents, in this case heroes-list.component, with a green background. I do not understand why the green here is bleeding below the screen when everything is set to 100%
Update I have tried using all manner of different CSS attributes to different levels in this nesting. Including 100vh vs 100%, min-height vs height, and every combination of body/html/home-container/my-page. I have also tried the same with Angular's CSS :host, to the same result of no different
Update2 If I move it out of the element then everything behaves as you'd expect and there's no vertical scroll bar. Something about the router-outlet wrapper adds vertical space somewhere but I cannot figure out where or what is causing it.
Final Update The below answers might be useful for some applications but I ended up just solving it by giving the .my-page a specified height, just doing height: calc(100vh - $headerheight - $subheaderheight) which gets the job done
As far as I understand, 100% on a child will be equal to the size of the parents natural height. If you want to fill the space available, you really should be using flex unless you have a requirement to support IE9 and below.
I would update your Anchors to be contained in a div (or another wrapper)
<h1 class="title">Component Router</h1>
<div>
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
<a [routerLink]="['Heroes']">Heroes</a>
</div>
<router-outlet></router-outlet>
I would then utilize flexbox to allow the content to expand as required
.hero-list {
background-color: green;
height: 100%;
overflow:auto
}
undefined {
flex: 1;
}
body, html, my-app {
height: 100%;
}
my-app{
display: flex;
flex-flow: column;
}
Plunker to test: http://plnkr.co/edit/yE1KOZMr1pd5jQKlVYIN?p=preview
On chrome i still have scroll bars due to an 8px margin on body - this can easily be removed with CSS for a scroll free full height experience.
There are two causes that make your <body> element taller than 100% of the viewport:
Default margins of the <body> element that come from the browser's built-in styles and usually are 8px. This means that the <body> element will be as tall as the <html> element, but also will have 8px space above it and below it, causing the <html> element to overflow.
The top margin of the <h1> element "falls out" from the container due to margin collapsing. This makes the space above the <body> element equal to the default top margin of <h1> (about 21px instead of 8px).
Setting zero margin to <body> (part of ToTaTaRi's answer) helps you to solve the 1st issue. To solve the second one, you should make the <body> element or (probably better) the .my-app container establish the new Block Formatting Context. The easiest and most cross-browser way for this is setting the container overflow:hidden (other options are display:flow-root, which works for modern Chrome/Firefox, or column-count:1, which works in IE10+ and all modern browsers, you can compare nearly all the options in this live example).
First of all you should reset browser default styles at least somehow like this:
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
Then you could achive what you want without a flex layout if prefered through splitting the page into a header section and main content section with a preset division... So lets say the heading and the links go together into a container div with i.e. a height of 20% and the main content which is at the moment hold in a tag "undefined" gets a height of 80%, if you now set the height of the app container to 100% or 100vh it should work as expected!
EDIT (because the topic is still open...):
Have you tried this css code like explained above, works like charm!?
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body, my-app {
height: 100%;
height: 100vh;
}
h1 , h1 + div {
height: 10%;
height: 10vh;
}
undefined {
display: block;
background-color: green;
min-height: 80%;
min-height: 80vh;
}
I've got a click style that involves tilting the element via a 3D rotate when clicked on. Here's what it looks like:
And here is a GIF of the effect working properly with a short list!
I have perspective on the parent div set at about 1500px, and the list div is set to inherit perspective. When this scrollable div gets really long, though, you start to see effects like this when clicking elements toward the bottom of the list:
I'm assuming this is because the perspective is applied to the entire height of the div, rather than just the visible height. I tried to resolve this by having the perspective of the list div inherit from the parent div (who's height is only the visible area), but this had no effect.
Any ideas on how to solve this?
Thank you!
EDIT: Relevant HTML:
<div class="container">
<ul class="artists">
<li>38 Special</li>
<li>A Flock Of Seagulls</li>
<!-- etc. -->
</ul>
</div>
Relevant CSS:
div.container {
position: relative;
height: calc(100% - 120px);
overflow: hidden;
perspective: 1500px;
}
ul.artists {
position: absolute;
top:0;
bottom:0;
left:0;
right:0;
/* Animation stuff, list styles, etc */
perspective: inherit;
overflow-y: auto;
overflow-x: hidden;
}
When pressed, a style like this is applied to the list item:
{
transform: rotate3d(4.05, 6.1635, 0, 15deg);
}
EDIT: Repro here:
http://codepen.io/anon/pen/LqAhK
Notice how as you scroll down the list, the perspective is applied as though the viewport is as high as the list itself, rather than the container - resulting in a different effect depending on your position in the list! How can I get perspective to be applied on the list items using the dimensions of the container only?
My best workaround would be to freeze the list and set a static height on the click event, but that has some side effects and is a somewhat hacky solution!
I'm not sure if this is what you're looking for, but...
ul.list li {
perspective: inherit;
}
...changing it so that the <li> elements themselves are what reset the perspective, rather than the container <ul>, seems to make all the elements appear the same.
http://codepen.io/anon/pen/zGpKk
I'm trying to add an image with the &::before pseudo element and place it on top of it's parent element by adjusting the padding/margin. I have not be able to place the img "on top" of it's parent element. It resides within the box of the parent. I have tried setting both elements to display:block. I have attempted to use relative/absolute positioning. I have adjusted margins/padding without a solution.
HTML:
<div class="foo">
<div class="title">title</div>
<div class="body">text</div>
</div>
LESS/CSS:
.foo {
display:block;
padding: 1em;
&:before {
background-image: url("bar.svg");
padding: .25in;
background-repeat: no-repeat;
background-position: top left;
background-position: top outside;
background-color: white;
content: "";
display: block;
max-width: (#column + .45in);
margin-left: -.15in;
margin-top:-.5in;
}
}
I would expect adjusting the value of the margins on the pseudo element would produce the expected result. However this is not the case. Is there a limitation I'm unaware of?
Thanks for your time and your help.
First, I assume by "on top" you mean displayed "before" the .foo element. I assume that based on what it appears you are trying to do with your code. Normally, I would interpret "on top" as a higher z-index and overlapping an element, but I don't think that is what you are asking.
Second, unless I am unfamiliar with something (definitely possible), there is no outside keyword for background-position; therefore, that would seem to be an error (though I would not expect it to cause the issue you face).
Third, I would think that your basic premise should be working. This fiddle demonstrates a shifting of the :before element to be "before" its .foo parent. It could be your mixed use of em units and in units is causing some issues. That would not be a good way to insure you get the positioning you want. I would keep your units in em.
Pseudo-elements are displayed inline by default. Also, they are placed within the content area of an element.
To make it appear 'on top' of that element, set the display to block.
Lastly, pseudo-elements should be initialized using the content property.
.foo::before {
content: url(./bar.svg);
display: block;
}
Shouldn't the content of my container be cut off when the container has border-radius?
Sample HTML and CSS:
.progressbar { height: 5px; width: 100px; border-radius: 5px; }
.buffer { width: 25px; height: 5px; background: #999999; }
<div class="progressbar">
<div class="buffer"></div>
</div>
As you can see I use border-radius on the container (.progressbar), but the content (.buffer) goes 'outside' the container. I'm seeing this on Google Chrome.
Is this the expected behavior?
P.S. This isn't about how to fix it, this is about whether it should work like this.
Is this the expected behavior?
Yes, as crazy as it sounds, it actually is. Here's why:
The default overflow for <div> elements (and most other things) is visible, and the spec says this about overflow: visible:
visible
This value indicates that content is not clipped, i.e., it may be rendered outside the block box.
In turn, §5.3 Corner clipping in the Backgrounds and Borders module says:
A box's backgrounds, but not its border-image, are clipped to the appropriate curve (as determined by ‘background-clip’). Other effects that clip to the border or padding edge (such as ‘overflow’ other than ‘visible’) also must clip to the curve. The content of replaced elements is always trimmed to the content edge curve. Also, the area outside the curve of the border edge does not accept mouse events on behalf of the element.
The sentence that I've emphasized specifically mentions that the overflow value of the box must be something other than visible (that means auto, hidden, scroll and others) in order for the corners to clip its children.
If the box is defined to have visible overflow, which like I said is the default for most visual elements, then the content is not supposed to be clipped at all. And that's why the square corners of .buffer go over the rounded corners of .progressbar.
Consequently, the simplest way to get .buffer to clip within .progressbar's rounded corners is to add an overflow: hidden style to .progressbar, as shown in this updated fiddle.
For anybody wondering what a fix would be. The easiest way would be to edit the css.
In the example given this would be a suitable fix:
.progressbar { height: 5px; width: 100px; border-radius: 5px; overflow: hidden; }
.buffer { width: 25px; height: 5px; background: #999999; }
<div class="progressbar">
<div class="buffer"></div>
</div>
Semantically speaking, it's best to simply add a border-radius inherit property to the inner div, hence the new class addition:
.buffer {
border-radius: inherit;
}
As a consequence, for others situation, you can preserve the use of overflow: auto if the content overflows your frae and you want to see everything.
The edges and corners of the parent container are covered by quilt elements, so the content of the parent element needs to be cropped, as long as the overflow value is set not visible, for example:
.parent {
overflow: hidden;
border-radius: 5px;
}
This question seems to point to the same defect, apparently this is a bug.
CSS3 border-radius clipping issues
Edit
Eek! BoltClock has mentioned that this is indended so I'll post this other SO question on the topic whilst I also hunt for a spec quote on this.
How do I prevent an image from overflowing a rounded corner box with CSS3?
Specification Link
Just for reference, I'll stick the relevant link in - but I can't find anything explicit to the example you've given.
CSS Backgrounds - Rounded Corners
This is what the specifications says, so this is the way it should work. But that doesn't mean that Chrome does it like that.
5.3. Corner Clipping
A box's backgrounds, but not its border-image, are clipped to the appropriate curve (as determined by ‘background-clip’). Other effects that clip to the border or padding edge (such as ‘overflow’ other than ‘visible’) also must clip to the curve. The content of replaced elements is always trimmed to the content edge curve. Also, the area outside the curve of the border edge does not accept mouse events on behalf of the element.
http://www.w3.org/TR/css3-background/#border-radius
Here's a question that's been haunting me for a year now. The root question is how do I set the size of an element relative to its parent so that it is inset by N pixels from every edge? Setting the width would be nice, but you don't know the width of the parent, and you want the elements to resize with the window. (You don't want to use percents because you need a specific number of pixels.)
Edit
I also need to prevent the content (or lack of content) from stretching or shrinking both elements. First answer I got was to use padding on the parent, which would work great. I want the parent to be exactly 25% wide, and exactly the same height as the browser client area, without the child being able to push it and get a scroll bar.
/Edit
I tried solving this problem using {top:Npx;left:Npx;bottom:Npx;right:Npx;} but it only works in certain browsers.
I could potentially write some javascript with jquery to fix all elements with every page resize, but I'm not real happy with that solution. (What if I want the top offset by 10px but the bottom only 5px? It gets complicated.)
What I'd like to know is either how to solve this in a cross-browser way, or some list of browsers which allow the easy CSS solution. Maybe someone out there has a trick that makes this easy.
The The CSS Box model might provide insight for you, but my guess is that you're not going to achieve pixel-perfect layout with CSS alone.
If I understand correctly, you want the parent to be 25% wide and exactly the height of the browser display area. Then you want the child to be 25% - 2n pixels wide and 100%-2n pixels in height with n pixels surrounding the child. No current CSS specification includes support these types of calculations (although IE5, IE6, and IE7 have non-standard support for CSS expressions and IE8 is dropping support for CSS expressions in IE8-standards mode).
You can force the parent to 100% of the browser area and 25% wide, but you cannot stretch the child's height to pixel perfection with this...
<style type="text/css">
html { height: 100%; }
body { font: normal 11px verdana; height: 100%; }
#one { background-color:gray; float:left; height:100%; padding:5px; width:25%; }
#two { height: 100%; background-color:pink;}
</style>
</head>
<body>
<div id="one">
<div id="two">
<p>content ... content ... content</p>
</div>
</div>
...but a horizontal scrollbar will appear. Also, if the content is squeezed, the parent background will not extend past 100%. This is perhaps the padding example you presented in the question itself.
You can achieve the illusion that you're seeking through images and additional divs, but CSS alone, I don't believe, can achieve pixel perfection with that height requirement in place.
If you are only concerned with horizontal spacing, then you can make all child block elements within a parent block element "inset" by a certain amount by giving the parent element padding. You can make a single child block element within a parent block element "inset" by giving the element margins. If you use the latter approach, you may need to set a border or slight padding on the parent element to prevent margin collapsing.
If you are concerned with vertical spacing as well, then you need to use positioning. The parent element needs to be positioned; if you don't want to move it anywhere, then use position: relative and don't bother setting top or left; it will remain where it is. Then you use absolute positioning on the child element, and set top, right, bottom and left relative to the edges of the parent element.
For example:
#outer {
width: 10em;
height: 10em;
background: red;
position: relative;
}
#inner {
background: white;
position: absolute;
top: 1em;
left: 1em;
right: 1em;
bottom: 1em;
}
If you want to avoid content from expanding the width of an element, then you should use the overflow property, for example, overflow: auto.
Simply apply some padding to the parent element, and no width on the child element. Assuming they're both display:block, that should work fine.
Or go the other way around: set the margin of the child-element.
Floatutorial is a great resource for stuff like this.
Try this:
.parent {padding:Npx; display:block;}
.child {width:100%; display:block;}
It should have an Npx space on all sides, stretching to fill the parent element.
EDIT:
Of course, on the parent, you could also use
{padding-top:Mpx; padding-bottom:Npx; padding-right:Xpx; padding-left:Ypx;}