CSS borders interfering with absolute positioning - css

[edit: clarified that box-sizing: border-box doesn't seem applicable, since I'm using absolute positioning]
The following code illustrates my problem. I'm using absolute positioning, because I found this even trickier with flow-based layout, but I'm open to suggestions. What I want is borders around arbitrary elements, without the borders affecting the positioning of the nodes. (The borders may clip or be overwritten by the content, but that doesn't matter.)
In particular, the borders of a parent must be able to overlap with the borders of its children, which is not the default behaviour. The CSS box-sizing attribute can be set to border-box to achieve the effect I want, but only (I believe) with inline elements. It has no effect on elements with absolute positioning (as I understand things).
So, my approach has been to use a negative margin to offset the positions of the children by the width of the border. This does indeed seem to cancel out the effect of the border's presence, but unfortunately not in a way which is consistent across scaling factors. At large scales, things look ok. At the default browser zoom in Chrome, the element positioning goes a bit off (they appear too high); if I go smaller, then the element position goes off in the other direction.
But if I remove the borders entirely, the layout seems to scale ok.
So my question is: is there a reliable (scalable) way to have borders on HTML elements with no impact on the positioning of the elements?
[In the example, I've used different colours for some of the borders. I would like to see only black, but at some zooms I can see red and green borders, showing that the element's position is being affected by the presence of the border.]
thanks
Roly
.bordered {
position: absolute;
height: 18px;
border: 2px solid;
margin: -2px;
}
<span class="bordered" style="width: 55px; left: 30px;">
<span class="bordered" style="width: 8px; left: 0;">
(
</span>
<span class="bordered" style="border-color: green; width: 47px; left: 8px;">
<span class="bordered" style="border-color: red; width: 39px; left: 0;">
<span class="bordered" style="width: 8px; left: 0;">
5
</span>
<span class="bordered" style="width: 31px; left: 8px;">
<span class="bordered" style="width: 23px; left: 8px;">
Nil
</span>
</span>
</span>
<span class="bordered" style="width: 8px; left: 39px;">
)
</span>
</span>
</span>

Try out CSS2 outline property:
.bordered {
outline:2px solid blue;
}
Outline does not affect element position.
You can also use CSS3 outline-offset as seen here: http://www.css3.info/preview/outline/

I also discovered that using a border of zero width (so that it doesn't affect layout), and then adding a box-shadow to emulate a visible border, seems to work well.

Six years later...
The other answers didn't work for my situation since the box I was styling already had a box-shadow. I needed a border on just one side like border-left and a border-radius, but without the border affecting the position or width of the element. The solution I came up with was to apply the border on an inner element of the absolutely positioned element.
.outer {
position: absolute;
width: 200px;
height: 100px;
border-radius: 5px;
background-color: #c8c8c8;
}
.inner {
height: 100%;
min-height: 100%;
min-width: 100%;
width: 100%;
border-left: solid 5px #097fee;
border-radius: 5px;
}
<div class="outer">
<div class="inner">
Some content
</div>
</div>

Related

CSS: Absolute element relative to inline multiline element

I have recreated my problem on this pen:
https://codepen.io/brennerp/pen/wOEebK
.example {
margin-right: 100px;
height: 100px;
max-width: 130px;
font-size: 16px;
line-height: 24px;
white-space: normal;
word-break: break-word;
}
.relative {
position: relative;
}
.absolute {
position: absolute;
top: calc(50% - 8px);
right: -21px;
width: 16px;
height: 16px;
border-radius: 50%;
background: blue;
}
<div class="example">
<span>
<span class="relative">
<span class="relative__label">
Wrong one asdsdasadsadsdasadas ts asdsadasdasdsadsajdkhsdjahas
</span>
<div class="absolute"></div>
</span>
</span>
</div>
I wanted to have a text of any size with an element absolute-positioned by its end, does not matter what size the text is. I have a relative-positioned inline element with two children: one inline element with its text and other absolute-positioned element with top:0 and right:0.
Just like the "Right one test[...]" example, the little blue circle is at the end and aligns with the middle of the text. However, the "right" property of the absolute element seems to respect one of the SMALLER LINES. In other words, if "right: 0;", the absolute element does not go to the right end of the relative element, but to the end of one of the smaller lines, just like the "Wrong one [...]" example. Which is NOT what I want. I want it to respect the size of the relative element, just like I forced on the CodePen.
Does anyone know the reason for the "right" property to respect the smallest line and not the relative element's width? Is that how inline elements work? Is there a solution for what I want: an absolute element that respects the end of a text element, whether if its 20px or 300px wide (just like the examples I put)?

How to officially auto size a container to its content when elements are absolutely positioned? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
What is the official way to auto size a container div to it's contents?
I want the "BorderContainer1056" to size to it's contents:
#BorderContainer1056 {
position: absolute;
top: 39px;
left: 100px;
width: 240px;
display: inline-block;
background-color: rgba(225, 225, 225, 1);
border-style: solid;
border-width: 1px;
border-color: #696969;
border-radius: 0px;
overflow: auto;
}
#VGroup1061 {
position: absolute;
top: 20px;
left: 20px;
overflow: visible;
text-align: left;
}
*,
*:before,
*:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
<div id="BorderContainer1056">
<div id="VGroup1061">
<span id="Label1063">Vertical Group in Container</span>
<span id="Label1064">Apple</span>
<span id="Label1065">Orange</span>
<span id="Label1066">Banana</span>
<span id="Label1067">Grape</span>
<span id="Label1068">Cherry</span>
<span id="Label1069">Mango</span>
<span id="Label1070">Kiwi</span>
<span id="Label1071">Pineapple</span>
<span id="Label1072">Strawberry</span>
</div>
</div>
Why can't their be a property on the container telling it to size to it's content?
Here is the running example, https://jsfiddle.net/bj354bcq/.
Specific information from a browser manufacturer or w3.org/standards/webdesign/htmlcss would be helpful.
The post linked to as a duplicate has a lot of "This is how I did it answers." They don't reference any official documentation or the W3 behaviors references. Those answer do not answer my question and do not work with the code above. So I'm asking the browser manufacturers or developers that know what an official method is.
UPDATE 2020:
Please reopen. I sort of figured out a way to handle it. Taken into account,
If all child elements of a container are absolutely positioned, the parent’s height will collapse to zero.
We can specify one element as the sizing element. This can be an element that grows or is the farthest bottom edge in the container. Set this element to position relative and remove the height on the container (and possibly also add position relative to the container. The container will then size, height wise, to the sizing element.
If you have other elements above or below in the DOM hierarchy you can do the same with those. Remove the height on the container, position it as relative and "stack" these elements.
I'll try to post an update with more code and instructions here. I can't add as an answer because someone closed this question. I've updated the question title in hopes it makes it clearer.
NOTE: Stack Overflow just awarded this question as notable!
UPDATE
To summarize:
#VGroup1061:
No position:absolute
#BorderContainer1056
No explicit width
Don't have a link for the second point yet, but it makes sense if you have a child at 120px and you want the parent to shrink at the size of content, then the width can't be set to 240px. Alternatives are: max-width, auto✲, etc.
Change your #VGroup1061 by removing position:absolute or change it to position: static or even position:relative. Positioning children elements in a positioned parent at a collapsed height of 0, and in your case where you want the parent shrinkwrapped on the child, it wouldn't be useful but actually detrimental.
This article is an official take on the subject from W3.
If all child elements of a container are absolutely positioned, the parent’s height will collapse to zero.
After adding position:absolute back to the Snippet (because it's irritating and made no difference to demonstrate what I intended to demonstrate), and making the child element position:static or relative and removing the fixed width of #BorderContainer1056 (the original "controlled" subject) makes it behave as OP wanted it to in the first place.
I believe the placement of the following rulesets✎ should go at the top of the stylesheet as well:
html,
body {
width: 100%;
height: 100%;
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
margin: 0;
padding: 0;
}
Placing powerful resets at the bottom of a stylesheet or block will undo everything (i.e. margins, padding, etc.) preceding it due to inheritance.
I just remembered that display:table-cell can do what you want as well, see updated Snippet, in particular #BorderContainer3056. display: table-cell works only if #BorderContainer3056 doesn't have an explicit width. Perhaps it could work if wrapped in another container with:
display:table;
table-layout: fixed;
In the Snippet below, there are 2 5 identical sets of a <section>, a <div>, and 10 <span>s.
Both <section>s have a pink background and green border.
Both <section>'s contents:
Contains a <div> which contains...
...10 <span>s
The <section>'s contents have a purple background and yellow border.
Notice the second set <section>'s green border wraps perfectly around it's content. This is possible by using the fit-content property or min-content
#BorderContainer2056 {
width: -moz-fit-content;
width: -webkit-fit-content;
width: fit-content;
}
fit-content can be found under CSS Intrinsic & Extrinsic Sizing Module Level 3 in the W3C Working Draft.
With the appropriate vendor prefix (see previous example), it can be used by Firefox and Chrome, but IE and Edge is a no go (no surprise there of course).
Note: This is called the “shrink-to-fit” width in CSS2.1§10.3.5 and CSS Multi-column Layout § 3.4.
#BorderContainer4056 {
width: -moz-min-content;
width: -webkit-min-content;
width: min-content;
}
min-content is referenced in the same area as fit-content
As LGSon pointed out it is experimental, for the last 10 years, but I'm sure he'll find a solution more suitable and official.
✎ The rulesets above are my version and varies with your original ruleset, but nevertheless it still applies.
✲ auto attributed to #LGSon's comments see ##BorderContainer5056 in Snippet.
SNIPPET
html,
body {
width: 100%;
height: 100%;
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
margin: 0;
padding: 0;
}
section {
position: absolute;
background-color: rgba(225, 0, 0, .4);
border-style: solid;
border-width: 3px;
border-color: green;
text-align: right;
width: 240px;
}
div {
position: relative;
overflow: visible;
text-align: left;
color: #ded;
}
span {
background: rgba(0, 0, 255, .4);
border: 1px solid gold;
display: block;
width: 150px;
}
#BorderContainer2056 {
width: -moz-fit-content;
width: -webkit-fit-content;
width: fit-content;
}
/* Separated for demo purposes */
#BorderContainer2056 {
top: 250px;
}
#BorderContainer3056 {
display: table-cell;
}
/* Separated for demo purposes */
#BorderContainer3056 {
top: 500px;
}
#BorderContainer4056 {
position: relative;
width: -moz-min-content;
width: -webkit-min-content;
width: min-content;
}
/* Separated for demo purposes */
#BorderContainer4056 {
top: 750px;
}
#BorderContainer5056 {
width:auto;
}
/* Separated for demo purposes */
#BorderContainer5056 {
top: 1000px;
}
<section id="BorderContainer1056">
BG1056
<div id="VGroup1061">
<span id="Label1063">Vertical Group in Container</span>
<span id="Label1064">Apple</span>
<span id="Label1065">Orange</span>
<span id="Label1066">Banana</span>
<span id="Label1067">Grape</span>
<span id="Label1068">Cherry</span>
<span id="Label1069">Mango</span>
<span id="Label1070">Kiwi</span>
<span id="Label1071">Pineapple</span>
<span id="Label1072">Strawberry</span>
</div>
</section>
<section id="BorderContainer2056">
BG2056
<div id="VGroup2061">
<span id="Label2063">Vertical Group in Container</span>
<span id="Label2064">Apple</span>
<span id="Label2065">Orange</span>
<span id="Label2066">Banana</span>
<span id="Label2067">Grape</span>
<span id="Label2068">Cherry</span>
<span id="Label2069">Mango</span>
<span id="Label2070">Kiwi</span>
<span id="Label2071">Pineapple</span>
<span id="Label2072">Strawberry</span>
</div>
</section>
<section id="BorderContainer3056">
BG3056
<div id="VGroup3061">
<span id="Label3063">Vertical Group in Container</span>
<span id="Label3064">Apple</span>
<span id="Label2065">Orange</span>
<span id="Label3066">Banana</span>
<span id="Label3067">Grape</span>
<span id="Label3068">Cherry</span>
<span id="Label3069">Mango</span>
<span id="Label3070">Kiwi</span>
<span id="Label3071">Pineapple</span>
<span id="Label3072">Strawberry</span>
</div>
</section>
<section id="BorderContainer4056">
BG4056
<div id="VGroup4061">
<span id="Label4063">Vertical Group in Container</span>
<span id="Label4064">Apple</span>
<span id="Label4065">Orange</span>
<span id="Label4066">Banana</span>
<span id="Label4067">Grape</span>
<span id="Label4068">Cherry</span>
<span id="Label4069">Mango</span>
<span id="Label4070">Kiwi</span>
<span id="Label4071">Pineapple</span>
<span id="Label4072">Strawberry</span>
</div>
</section>
<section id="BorderContainer5056">
BG5056
<div id="VGroup5061">
<span id="Label5063">Vertical Group in Container</span>
<span id="Label5064">Apple</span>
<span id="Label5065">Orange</span>
<span id="Label5066">Banana</span>
<span id="Label5067">Grape</span>
<span id="Label5068">Cherry</span>
<span id="Label5069">Mango</span>
<span id="Label5070">Kiwi</span>
<span id="Label5071">Pineapple</span>
<span id="Label5072">Strawberry</span>
</div>
</section>
What is the official way to auto size a container div to it's contents?
It depends among others on which display property, block, inline-block, inline, table-cell, etc., and position property, static, relative, absolute, etc., is used.
Src: https://www.w3.org/TR/CSS2/visuren.html#propdef-display
Why can't their be a property on the container telling it to size to it's content?
There is, though it is not one property, it is several, width/height, max-width/height, min-width/height, etc., so we can control exactly how it should size itself using property values like auto, percent, px, vh, vw, etc..
Src: https://www.w3.org/wiki/CSS/Properties#Box_Size
At MDN and W3C one can read more about upcoming sizing features like fill, available, min/max/fit-content, etc., some more rolled out, some less.
Based on your question's sample (and comment), here is a few samples for absolute positioned div.
Element with position: absolute do size itself to its content, if it has normal flowed content,
div {
position: absolute;
background: lightblue;
}
<div>Hi there, ...<br>...how are you? </div>
but in your case, it's non normal flowed content, a second absolute positioned element, which has normal flowed content. The inner element will act as the above, and size itself to its content, and the outer will too actually, though its size is 0.
This happens because absolute positioned elements is taken out of flow and as such they render as if they where alone on a web page, so here the outer "don't know" there is an inner, hence doesn't become visible.
div {
position: absolute;
}
.outer {
background: lightblue;
}
.inner {
border: 1px solid gray;
}
<div class="outer">
<div class="inner">Hi there, ...<br>...how are you? </div>
</div>
Why your sample doesn't show anything is because you used overflow:auto, which expects a height or else it will collapse the elements height and only grow with normal flowed content.
div {
position: absolute;
}
.outer {
background: lightblue;
overflow: auto;
}
.inner {
border: 1px solid gray;
}
<div class="outer">
<div class="inner">Hi there, ...<br>...how are you? </div>
</div>
<hr>
<div class="outer">
Normal flowed content
<div class="inner">Hi there, ...<br>...how are you? </div>
</div>

Disable overflow scrolling on webkit-based browsers

I'm using ::after to create shadow to decorate a element (say A).
In order to do this, I set the overflow: hidden for A to hide undesired part of the shadow.
It looks perfect, but there is a problem after I added a input box to A. If I click in the input and drag, the A layer will scroll, and the rest part of shadow will show up.
Here is the demo and the simplified code:
<div style="width: 200px; height: 30px; overflow: hidden; border: 1px black dotted;">
<div style="height: 30px; border-bottom: red 10px solid;">
<input style="width: 200px" placeholder="click and drag me downward" />
</div>
</div>
I'm looking for a pure CSS solution to fix this problem. Thanks ahead.
This isn't an ideal solution, but I don't think a pure CSS solution exists to this problem (unfortunately), it makes me wonder whether this has been logged as a bug with the Chrome team.
jQuery should be as follows:
$('input').on('mousedown', function(e){
$(e.target).focus();
e.preventDefault();
});
(I know I shouldn't assume you're using jQuery, if needed I can provide you a pure JS solution, it'll just be more complicated).
Fiddle: http://jsfiddle.net/jzb5a/
EDIT: Apparently this is a known bug (https://bugs.webkit.org/show_bug.cgi?id=114384) it's dissapointing that four months on there still hasn't been a fix though.
Finally come to an solution, which is not that perfect but fixed the problem anyway.
As the background overflows, and the input on the same layer would cause the problem. So just move the input to another layer which doesn't overflow. demo
<div style="position: relative; width: 200px; height: 30px; border: 1px black dotted;">
<div style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; z-index: -1; overflow: hidden;">
<div style="height: 30px; border-bottom: red 10px solid;"></div>
</div>
<input style="width: 160px" placeholder="click and drag me downward" />
</div>

Relative positioning appears differently in IE7 than other browsers

I have two divs both have position relative on them. The inner div has left and top position. They work fine in all browsers except in IE7 it appears the left position needs to be about 100px less. I'm wondering if I can fix this without having to have a IE specific stylesheet.
Here is the code
<div style="position:relative;">
<div class="edit-photo-div">
<a href="#">
<span class="edit-photo-icon">Edit</span>
</a>
</div>
</div>
and my css:
> .edit-photo-div {
background-image: url("/images/editphoto.png");
background-position: 9px 6px;
height: 28px;
left: 143px;
position: relative;
top: -27px;
width: 35px;
margin-bottom:-29px;
overflow:hidden;
}
.edit-photo-icon{
padding-left:35px;
position:relative;
top:6px;
color:#7c7c7c;
font-weight:bold;
}
jsFiddle link
I've run into issues before older versions of IE when I put "position: relative" into span elements. Try taking that out and see if it makes a difference. Also for ".edit-photo-div" try making that absolutely positioned. You already set the "top" and "left" so it should stay in the same place.

Highlighting a field in a table and have it print

Does anyone know how to yellow highlight a field in table and also have the yellow color print? This hightlights on the screen, but does not print the yellow:
<td style="background-color: yellow">Total:</td>
I found out that browsers, by design, do not print background colors. The only workaround I was able to find is that you can make a ultra-thick border of the cell or div:
<td style="border-left: 999px solid yellow">
Unfortunately, the cell contents won't overlay over the thick yellow border. I checked everywhere online and the closest answer I could find was on stack overflow:
Best Ways to Get Around CSS Backgrounds Not Printing
However, the answer was untested and I was unable to get it working on my computer. I tried toying around and experimenting with no luck.
Ok, I found a solution to my problem, but the solution is rather inelegant. Like I said in my above question, you have create a div tag with a big color border on it. The thing is is that colored borders can print correctly. Then, where the highlighted color is displayed, lay another div tag with the text on top. Inelegant, but it works.
It's best to set both the text div and the highlight div's within a third "outer" div for easy placement. the inner divs should be position "absolute" and the outer div should have position "relative". Sample code is below. This is tested code on both Chrome and Firefox:
<style type="text/css">
#outer_box {
position: relative;
border: 2px solid black;
width: 500px;
height:300px;
}
#yellow_highlight {
position: absolute;
width: 0px;
height: 30px;
border-left: 300px;
border-color: yellow;
border-style: solid;
top: 0;
left: 0px
}
#message_text {
position: absolute;
top: 0;
left: 0px;
}
</style>
<body>
<div id="outer_box">
<div id="yellow_highlight"> </div>
<div id="message_text">hello, world!</div>
</div>
</body>

Resources