min-height, height, class, id precedence - javascript

I have a class that receives the same height across the project. I want one div that is a member of the class to expand dynamically. So I give the div an ID (more specificity). I was also under the impression that min-height would take precedence over height (which should allow div expansion). But the div will not expand when its class has a height set. It works if I remove the height, but shouldn't there be two degrees of more specificity in this case? Here's the fiddle:
Working: http://jsfiddle.net/farinasa/WHn9t/
Not working: http://jsfiddle.net/farinasa/WHn9t/2/
HTML:
<div id="specific" class="lessSpecific">
</div>
CSS:
.lessSpecific
{
border: 1px solid black;
height: 100px;
}
#specific
{
min-height: 300px;
}
JS:
var box = document.getElementById("specific");
function test() {
for (var i = 0; i < 20; ++i)
box.innerHTML += "Hello<br>";
}
test();

Min-height does not take precedence over height. The ID's rules take precedence over the class' rules. Therefore, add a height: auto to the ID selector and you've nullified the static height for that container.
http://jsfiddle.net/WHn9t/3/
I find it useful to refer to W3Schools to find CSS default values for situations like this where a rule needs to be reset for a specific element. http://www.w3schools.com/cssref/pr_dim_height.asp
.lessSpecific
{
border: 1px solid black;
height: 100px;
}
#specific
{
min-height: 300px;
height: auto;
}
or this if you prefer
.lessSpecific
{
border: 1px solid black;
height: 100px;
}
#specific.lessSpecific
{
min-height: 300px;
height: auto;
}

Related

Manipulation of HTML objects added with appendChild in Javascript

I am using a Javascript function to try to add several div elements to an HTML page. The objects show up but they appear to be joined together. I can apply some css such as background-color and width and height, but I can't see how to change properties like top and left. I have tried putting them into a table generated with createElement, but they are still joined together. Is there a way to make the elements seperate after they are added this way? Thanks.
The css
.block {
display: inline-block;
width: 200px;
height: 200px;
top: 200px;
left: 200px;
border: solid 1px black;
background-color: aquamarine;
}
#container {
width: 100%;
height: 200px;
display: flex;
}
The javascript
function setup() {
word = "test";
container = document.getElementById("container");
for (let counter=0;counter<word.length;counter++) {
block = document.createElement("div");
block.innerHTML = word[counter];
block.className = "block";
container.append(block);
}
}

Why is scrollWidth not including a child element's right margin?

I'm trying to have a <div> slide open to the minimum size required to contain its content without anything overflowing.
Here's what I've got so far:
window.onload = function() {
setTimeout(() => {
var thing = document.getElementById('thing');
thing.style.maxWidth = thing.scrollWidth + "px";
thing.style.maxHeight = thing.scrollHeight + "px";
}, 1000);
}
body {
background-color: black;
}
p {
margin: 40px;
padding: 0;
color: yellow;
background-color: green;
font-family: monospace;
}
div.expander {
margin: 0;
padding: 0;
max-width: 0;
max-height: 0;
overflow: hidden;
transition:
max-width 1s,
max-height 1s;
border: 1px solid red;
}
hr {
margin: 0;
padding: 0;
border-top: 1px solid blue;
border-right: none;
border-bottom: none;
border-left: none;
}
<div id="thing" class="expander">
<p>Hello, world!</p>
<hr>
<p>Goodbye, world!</p>
</div>
See how neither <p> is wide enough to contain its text without overflowing? That's what I'm trying to prevent. Clearly, scrollHeight is doing what I expect. Why isn't scrollWidth?
This isn't the full picture, but margin-right (or margin-left) gets ignored in specific scenarios. This is intended block functionality in CSS. From the specs:
'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block
If all of the above have a computed value other than 'auto', the values are said to be "over-constrained" and one of the used values will have to be different from its computed value. If the 'direction' property of the containing block has the value 'ltr', the specified value of 'margin-right' is ignored and the value is calculated so as to make the equality true. If the value of 'direction' is 'rtl', this happens to 'margin-left' instead.
In my opinion, this isn't very intuitive behavior and I prefer to avoid margins for block layout where possible (for more reasons than just this). So, you could add a wrapper <div> around your <p> tags and use padding instead. This also enables you to use a border between items instead of adding <hr> to your content. I think the proper semantics could go either way, depending on your real-world usage of this. To quote the MDN docs:
The HTML <hr> element represents a thematic break between paragraph-level elements: for example, a change of scene in a story, or a shift of topic within a section.
Historically, this has been presented as a horizontal rule or line. While it may still be displayed as a horizontal rule in visual browsers, this element is now defined in semantic terms, rather than presentational terms, so if you wish to draw a horizontal line, you should do so using appropriate CSS.
But, while that fixes a few concerns, that doesn't fix everything. The calculated width of the <p> elements is still less than min-content. So, we can force this with min-width: min-content;, or by using a different display value (probably on expander). This changes which algorithms are used for calculating widths under the hood.
Last note before the full example code: max-width and max-height are a decent trick but are really only useful for this kind of thing if you're trying to avoid modifying styles from JS (think :hover or adding and removing an .open class from JS, instead of setting width and height, directly)
setTimeout(() => {
const expander = document.querySelector('.js-expander');
expander.style.width = expander.scrollWidth + "px";
expander.style.height = expander.scrollHeight + "px";
}, 1000);
body {
background-color: black;
}
.expander {
display: grid;
width: 0px;
height: 0px;
overflow: hidden;
border: 1px solid red;
transition:
width 1s,
height 1s;
}
.expander-item {
padding: 40px;
font-family: monospace;
border-bottom: 1px solid blue;
}
.expander-item:last-child { border-bottom: 0px; }
.expander-item > * {
color: yellow;
background-color: green;
}
.expander-item > :first-child { margin-top: 0; }
.expander-item > :last-child { margin-bottom: 0; }
<div class="expander js-expander">
<div class="expander-item">
<p>Hello, world!</p>
</div>
<div class="expander-item">
<p>Goodbye, world!</p>
</div>
</div>
UPDATE: Based on comments, I thought I might include how <hr/> might be added back in:
setTimeout(() => {
const expander = document.querySelector('.js-expander');
expander.style.width = expander.scrollWidth + "px";
expander.style.height = expander.scrollHeight + "px";
}, 1000);
body {
background-color: black;
}
.expander {
display: grid;
width: 0px;
height: 0px;
overflow: hidden;
border: 1px solid red;
transition:
width 1s,
height 1s;
}
.expander-group {
padding: 40px;
font-family: monospace;
}
.expander-group > * {
color: yellow;
background-color: green;
}
.expander-group > :first-child { margin-top: 0; }
.expander-group > :last-child { margin-bottom: 0; }
.expander > hr {
margin: 0;
padding: 0;
border-top: 1px solid blue;
border-right: none;
border-bottom: none;
border-left: none;
}
<div class="expander js-expander">
<div class="expander-group">
<p>Hello, world 1!</p>
<p>Hello, world 2!</p>
</div>
<hr>
<div class="expander-group">
<p>Goodbye, world!</p>
</div>
</div>

How to set element to grow horizontally instead of breaking to a new line?

I'm facing problem with breaking the line on website. What do I mean?
HTML code
<main class="clearfix">
<div class="first"></div>
<div class="second"></div>
<div class="third"></div>
</main>
<button>Add</button>
With such HTML code I'd like to have:
fixed height on main element (for example 80vh)
fixed height for all the elements first and third 40vh + second 80vh
fixed width for first and third element 50vw
fluid width for second element - but this is main problem - second element has to be in the same place and grow horizontally (to create scroll on the bottom of the site)
Please find my codepen
I've added button that'll add pixels to second element - but it destroys my website.
I'm not sure if flexbox is better than floats.
I'll appreciate any tip.
Here is the snippet:
let counter = 0;
document.querySelector("button").addEventListener("click", function() {
document.querySelector(".second").style.width = `calc(50% + ${counter}px)`;
console.log(counter);
counter++;
});
* {
padding: 0;
margin: 0;
}
main {
max-height: 80vh;
}
.first,
.third {
height: 40vh;
width: 50vw;
background-color: black;
float: left;
}
.third {
background-color: red;
}
.second {
height: 80vh;
width: 50%;
float: right;
background-color: blue;
}
.clearfix::after {
content: "";
display: table;
clear: both;
}
<main class="clearfix">
<div class="first"></div>
<div class="second"></div>
<div class="third"></div>
</main>
<button>Add</button>
I would suggest you to go with position properties. Since you have a little difference between the order of your DOM element and their visual representation, like 1,2,3 in the DOM, but visually it's more like 1,3,2.
However, in such situation float is your enemy. I'm not 100% sure about flex, AFAIK flex would keep all the elements inside the parent element and prevent the scrolling.
If you go with absolute positioning, (since you already have the heights and widths defined)
Apply:
position: relative to the main element, it will be the base point of the child elements if they are set to absolute.
overflow-x: scroll to the main element. it will allow you to scroll horizontally when you increase the width of your second element.
position: absolute on .first, .second, .third, as you have the height and width defined, now set their position accordingly, check the snippet, you'll get it.
Finally you're good to add more value to your width of the target element.
Tip: always keep a consistency in your css units, for example, if used vh / vw use this for similar elements at least, or if px / em / rem is used, try to use the same accordingly.
Check the snippet in full page mode
let counter = 0;
document.querySelector("button").addEventListener("click", function() {
document.querySelector(".second").style.width = `calc(50vw + ${counter}vw)`;
document.querySelector("#added").textContent = counter;
counter++;
});
* {
padding: 0;
margin: 0;
}
main {
overflow-x: scroll;
position: relative;
min-height: 80vh;
}
.first,
.third {
height: 40vh;
width: 50vw;
background-color: black;
position: absolute;
left: 0;
top: 0;
}
.third {
background-color: red;
top: 40vh;
}
.second {
height: 80vh;
width: 50vw;
background-color: blue;
position: absolute;
left: 50vw;
top: 0;
}
button {
margin: 30px 5px;
border: 1px solid #cecece;
padding: 5px 10px;
}
<main>
<div class="first"></div>
<div class="second"></div>
<div class="third"></div>
</main>
<button>Add</button>
<p><span id="added">0</span>vw Added to blue div's width</p>

Why inner element width doesn't increase when dynamic content is added to outer container

When I add dynamic content to .innerright. Why doesn't the width of .a increase dynamically. What should I do it to make sure .a takes width of .innerright container dynamically. I use javascript code to add the content dynamically.
var list = '';
for (var i = 0; i < 100; i++) {
list = list + i + 's';
}
$('.innerright').append(list);
.outer {
width: 500px;
height: 200px;
background-color: red;
}
.innerleft {
width: 20%;
float: left;
height: 100%;
background-color: yellow;
}
.innerright {
width: 80%;
height: 100%;
float: left;
background-color: green;
overflow: scroll;
}
.a {
height: 20px;
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="outer">
<div class='innerleft'>
</div>
<div class='innerright'>
<div class="a">
</div>
</div>
</div>
It's because you set a calculated width on the container element and specifically tell the container to deal with overflowing content by adding a scroll bar.
As far the css is concerned the element is always at it's calculated width and the extra content just expands into the overflow area rather than affecting the container's width.
I'm not sure this is fixable in css alone while maintaining the overflow property to scroll. Everything is doing as it should, the elements are taking the widths they should take and that is being maintained throughout dynamic content editing - overflow is not part of width.
You could use the javascript scrollWidth value and use that to dynamically edit the width of the .a element.
See the fiddle here
The important bit is:
$('.a').width($('.innerright')[0].scrollWidth);
which gets the scroll width of the .innerright element, that includes the width and the overflow and uses that to set the width of the .a element, which also now goes into the overflow area.
And of course, you'll need to call and recall this after you add any dynamic content!
NB, the [0] means get the first element in the array of DOM nodes returned by the JQuery call.
As others pointed out, block elements don't grow, they overflow. You're CSS makes that overflow scrollable. In order to acheive your goal, wrap the content (<a> and text) in an inline-block element, which will grow, and now you're <a> will receive it's parent (grown) width, and the <div> will still have scrollable overflow:
var list = '';
for (var i = 0; i < 100; i++) {
list = list + i + 's';
}
$('.contentspan').append(list);
.outer {
width: 500px;
height: 200px;
background-color: red;
}
.innerleft {
width: 20%;
float: left;
height: 100%;
background-color: yellow;
}
.innerright {
width: 80%;
height: 100%;
float: left;
background-color: green;
overflow: scroll;
}
.a {
height: 20px;
border: 1px solid red;
}
.contentspan {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="outer">
<div class='innerleft'>
</div>
<div class='innerright'>
<span class='contentspan'>
<div class="a">
</div>
</span>
</div>
</div>
By the way, this has nothing to do with dynamic content or JS. If the text was inlined in the HTML you'd get the exact same results.

How to make div take all the height available?

I have this HTML:
<div>
<span></span>
<textarea></textarea>
</div>
The Span can take up one or more lines (depends on the text it has and size of the Div). I want the Textarea to take all of the height left in div.
Please no jQuery.
https://jsfiddle.net/ntme8Lt4/
The CSS/style tag for that would just be max-height:100%; and width:100%;
This would hold the div's size constant if it is set to a percentage of its parent container or a constant value like 900px.
Since the size of span is not known, just leave it unspecified so it auto-sizes to content.
There's a circular issue here - the height of the div is (normally) determined by the size of its components. You need something to break the circle and determine the height of either the div or the text area.
You can use offsetHeight to get the heights of the different elements, and from there it is just a calculation of the container - span element to find the remaining.
document.querySelector('textarea').style.height = (document.querySelector('div').offsetHeight-document.querySelector('span').offsetHeight)+'px'
http://jsfiddle.net/rhbritton/4eck8dua/1/
If you're just wanting to use pure CSS and without the needs of tables etc you could try this approach.
HTML:
<div>
<span>
Hello<br>
Hello<br>
Hello
</span>
<textarea></textarea>
</div>
CSS:
div {
width: 400px;
height: 300px;
overflow: hidden;
border: 1px solid red;
}
span {
width: 100%;
display: block;
background-color: red;
}
textarea {
width: 100%;
height: 100%;
background-color: blue;
}
JSFiddle
Let me know if this works for you.
You can use clientWidth and clientHeight if your willing to use pure JS:
Here is the fiddle
function test()
{
var div = document.getElementById("testDiv");
var span = document.getElementById("testSpan");
var textArea = document.getElementById("testTextArea");
var height = div.clientHeight - span.clientHeight;
textArea.style.height = (height - 5) + "px";
textArea.style.width = (div.clientWidth - 5) + "px";
}
test();
Reference
you can use flex
div
{
display: flex;
flex-direction: column; /*layout top to bottom*/
height: 300px;
width: 400px;
border: 1px solid red;
}
span
{
display: block;
background-color: red;
}
textarea
{
background-color: blue;
height: 100%;
width: 100%;
flex-grow: 1; /*take up remaining space in flex container*/
}
}
https://jsfiddle.net/ntme8Lt4/13/
Thanks to the "possible duplicate" I came up with this solution:
<div>
<span>Hello<br>World</span>
<b><textarea></textarea></b>
</div>
div
{
height: 300px;
width: 400px;
border: 1px solid red;
display: table;
}
span
{
display: block;
background-color: red;
}
b
{
height: 100%;
width: 100%;
display: table-row;
}
textarea
{
height: 100%;
width: 100%;
background-color: blue;
}
https://jsfiddle.net/c42go079/

Categories

Resources