This seems like a suspiciously straight-forward question but having searched StackOverflow and Google and used the usual tricks (getBoundingClientRect, clientWidth, offsetWidth) I've yet to find an answer.
Simply, is there a way to find the width/height of an element including not only border, padding etc, but also the shadow?
See: jsfiddle for an example of how everything returns the width of the element without the shadow.
EDIT: Ideally, I'd prefer not to have to investigate the CSS attribute for the shadow and parse out the dimensions, though perhaps that's the only way.
You're right, I agree it's a pretty straight forward question. Here's the problem, when you give an element a box-shadow, the box-shadow is treated like a sub-element with absolute positioning properties to it's parent element. So automatically the placement of that object under it's parent becomes a relative positioning question. They are essentially now two separate objects and need calculated separately.
My only suggestion would be to calculate the box-shadow's x/y positioning and add them to the width/height of the parent element. For example, in your jsfiddle, the box shadow is protruding 10px along the x-axis, and below 10px along the y-axis. With the 5px blur, add 2.5px to either side and then add the height/width to those values:
104px (width) + 10px (x-axis shadow extension) + 2.5 px (blur) = 116.5px width
104px (height) + 10px (y-axis shadow extension) + 2.5px (blur) = 116.5px height
Use a shadowParent class
Here's another technique which worked well in one specific case for me:
Make a shadow parent class which affects it's height, having the same values as the shadow of the child. If you need to, make a new parent div just for this purpose. You can use CSS classes for this, for example: shadow and shadowParent.
Then whenever you need height+shadow, just get the height of the parent.
Advantages:
Less complexity in JS trying to figure out height.
You control the values in one place (wherever you define the CSS
values).
In this case, I simply set some padding on the parent, to account for the childs' shadow. Then I get the height of the parent.
/* ----------------------- */
/* SHADOW */
/* ----------------------- */
.shadow {
box-shadow: 0px 10px 10px black;
}
.shadowParent {
/* Apply matching values to some property that affects parent height. */
/* I used padding, which worked for my context. */
padding-bottom: 10px; /* Value matches shadow values. */
}
<div id="wrapper" class="shadowParent">
<div id="content" class="shadow">
Content + shadow
</div>
</div>
Related
I am using a js library (mermaid) to generate svg on a web page. I need to dynamically apply styling to parts of the svg as the user activates various commands using keyboard shortcuts, Particularly, I need to highlight the element in the svg that is currently designated as the selected one in the logical model. Looking at other questions on dynamically styling svg deal with inlined static svg, so they probably don't apply to my case and none of the methods I tried so far have worked.
The style I am trying to apply is
border-radius : 2rem; box-shadow : 0 0 3rem red;
when applied to regular html, this gives the element a glowing red border.
First thing I've tried was to include this as a class in a element in like this :
<style>
.highlight {
border-radius : 2rem;
box-shadow : 0 0 3rem red;
}
</style>
Adding the class to a regular html element 's class list like an , , or , would produce the desired styling. However when I would programmatically get a element and add the class to its class list, then it would remain without the glowing border. Inspecting the svg using chrome developer tools revealed that the relevant class has been added to the element's class list. Using the same method was successful for regular html. For reference here is the method I used to add the class:
graphicDiv.querySelector(selector).classList.add('highlight')
This having failed, I thought maybe the svg had some styling inside its internal element that overrode my styling, so I added !important to my styles so they would have highest precedence. This still failed to work, so next I tried to set the style property for the element, which should have the highest precedence like this:
graphicDiv.querySelector(selector).setAttribute('style', 'border-radius : 2rem !important; box-shadow : 0 0 3rem red !important;')
This still failed to produce any difference in the styling of the svg. Inspecting the element in chrome dev tools revealed the style attribute was indeed set.
I also tried adding my style definition to the svg's own element, by getting it after the svg is generated, and appending my class style definition to its text content. It would still not work.
Finally, I thought those css properties might not be supported by , so I changed them to background-color: green; instead, since I think I saw in an article on styling svg with css that this css prop was used on an . This didn't work. I tried applying to a element in the svg. Didn't work either.
I am completely baffled why none of this is working. I would massively appreciate if anyone could help me understand how I could dynamically change the styling of svg elements!
While normal CSS attributes can be given to SVG elements, most do nothing as SVG elements by definition adhere to a different set of styling rules.
A simple example is that in normal CSS you might set left: 25px but for SVG you would need to set x: 25.
For the styling you want, border radius is usually achieved with stroke-width. For background colour just use fill. As for a shadow, it may be a little more complex but you should have a look at feDropShadow.
Besides that, applying those styles with css rules should be roughly the same.
I hope that's at least some help.
This question already has answers here:
CSS margin terror; Margin adds space outside parent element [duplicate]
(7 answers)
What is the point of CSS collapsing margins?
(1 answer)
How to disable margin-collapsing?
(12 answers)
Closed 3 years ago.
I've never read anything to suggest that the overflow property of an element would have the strange effect on element positioning that I'm seeing here:
https://codepen.io/kshetline/pen/ZEzLVxN
Toggle the toggle button in the example, and watch how somehow the background of a <div> mysteriously slides upward, covering previous content, while its contents stays in the same screen-relative place (meaning the content is moving lower relative to its parent's background).
The example is a very simplified version of something I'm trying to do with an Angular component that's meant to scale its <ng-content> — but the example is only CSS and HTML with a tiny touch of JavaScript, no Angular, since I'm trying to isolate the relevant variables.
The content of an HTML element can be scaled down using transform: scale( less-than-1 scaling factor ), but even though the content of the element is rendered smaller, by default the element's pixel dimensions remain the same, with the content (unless otherwise specified) shrinking toward the center of the element, and blank space left around that content that leaves the element at its original unscaled dimensions..
You need to compute negative margins that match the degree of scaling in order for the element itself to be considered smaller. I've done that, but I've found that unless the container for the scaled element has CSS overflow set to hidden, some weird positioning can occur, as if the extra blank space required that's supposed to be removed by the negative margins is still having some partial, hard-to-explain effect on the overall layout of other elements.
I'm seeing this behavior in Chrome, Firefox, Safari and Edge -- so I'm guessing it's "proper" CSS behavior, but it makes no sense to me, and I'm hoping someone can explain what's going on. I'd like to be able to keep overflow set to visible so that scaled content can still do things like show floating dropdown menus that don't get clipped at the boundaries of the element.
let hidden = true;
const inner = document.getElementById('inner')
function toggleOverflow() {
hidden = !hidden;
inner.style.overflow = hidden ? 'hidden' :
'visible'
}
html, body {
height: calc(100vh - 10em);
}
.page {
font: 32px Arial, Helvetica, sans-serif;
height: calc(100% - 1em);
}
.container {
background-color: #ACF;
height: 100%;
}
.outer-wrapper {
background-color: rgba(187, 255, 204, 0.5);
font-size: 2em;
margin: 0 1em;
position: relative;
}
.inner-wrapper {
overflow: hidden;
position: relative;
width: fit-content;
}
.ng-content {
margin: -18.75px 0;
transform: scale(0.5);
}
.container-text {
display: inline-block;
position: absolute;
bottom: 1em;
}
<div class="page">
<button onclick="toggleOverflow()">Toggle Overflow</button><br>
Content outside of the<br>
panel being scaled and its<br>
containing <div>, 32pt font<br>
<div class="container">
<!--Angular component start tag goes here -->
<div class="outer-wrapper">
<div id="inner" class="inner-wrapper">
<div class="ng-content">
50% scaled content goes here, 64pt font
</div>
</div>
</div>
<!-- Angular component end tag goes here -->
<span class="container-text">This is an absolutely positioned <span> in the same <div></span>
</div>
</div>
From CSS 2.2 spec
Margins of elements that establish new block formatting contexts (such as floats and elements with 'overflow' other than 'visible') do not collapse with their in-flow children.
So adding overflow:hidden is stopping the margins from collapsing.
You have set a negative margin in your .ng-content. If overflow is set to hidden, it will hide the negative margin. Set the margin to a positive number and it will fix this jumping issue.
.ng-content { margin: 18.75px 0; }
If you are trying to change the height of the element up and down, try using max-height with overflow: hidden. When max height is set to 0, it will be hidden. When set to something like 500px, your content will show!
Follow-up...
I created a variant on my first code pen here:
https://codepen.io/kshetline/pen/WNeRmOo
In this case, I'm using transform-origin: top center when I scale, and putting all of the needed negative margin on at the bottom of the scaled element, rather than splitting it evenly between top and bottom. That eliminates the weird vertical position shifting.
overflow: hidden is still needed to hide the excess of background color from "leaking out" of its container, but in the (common) case where the background of the scaled element is transparent, there would be no visible effect from using overflow: visible instead, and no worries about clipped dropdown menus originating inside the scaled element.
Follow-up #2...
Here's the best solution, using padding: 0.05px to deal with the real issue that #Alochi helped me understand — stopping border collapse:
https://codepen.io/kshetline/pen/zYONgzV
I'm unable to get the border width of an element. I tried the following but it shows empty results. Check http://jsfiddle.net/s7YAN/14/
$('div').css('borderWidth');
borderWidth is syntactic sugar for setting each border's width independently. You can't assume that every border's width is the same, so you need to ask for a specific border's width.
$("div").css("borderTopWidth");
For border-width, you need to specify the side of the border. borderWidth/border-width is a shortcut for all of the border-width's at once.
$( function() {
alert($('div').css("border-top-width"));
});
http://jsfiddle.net/ZsSmp/
Also, you need to specify more than a border width for it to be valid. Just specifying a border-width does not make a border. It needs a color and style, too:
border: 2px solid black;
The problem is you don't define the border-style in your CSS, so it's default to none, whose width is 0px.
Also, you should specify which border (left, top) for border-width is just a shortcut for all borders.
The width of the div "topNav" changes by few pixels when its position style is changed from relative to fixed. I found a jquery plugin (http://imakewebthings.github.com/jquery-waypoints/) which can perform the same functionality I'm looking for elegantly, but I feel it is a overkill for this purpose.
EDIT: My question is how to avoid changing the div sizes.
Check out the code at :
http://jsbin.com/azace5/edit
You need to remove the page's "default margin". This will do it in "every browser":
html, body {
margin: 0;
padding: 0
}
See: http://jsbin.com/azace5/2
Or you can add a minimum width.
min-width:600px;
What causes this to happen? (the mouse is not being moved or clicked)
I suspect that the :hover CSS style results in the object having a different size (possibly margin), which causes the :hover CSS style to cease to be applied. This returns the object to its original dimensions, and the :hover CSS style is applied by the browser once more.
The browser can only keep up with this at a certain rate and you see visible flickering.
It's an edge condition.
It is because you are adding a border on hover.
But because you hover near the top, when the border is added, your cursor goes outside of the element.
Would be best to add
border: 1px solid #FFFFFF;
border-bottom: 0px;
to begin with, in your CSS
At a guess, the rollover event is adding a border which changes the effective size of the element, so that the mouse is no longer over it, or something like that...