Please note the following HTML for a Tabbed display (for an option page):
I would like to maintain the same height as tab1 for tab2 and tab3
<article>
<nav> <!-- content --> </nav>
<section id="tab1"> <!-- content --> </section>
<section id="tab2"><iframe src=""></iframe></section>
<section id="tab3"><iframe src=""></iframe></section>
</article>
tab1 always loads first with display: block; and both tab2 & tab3
have display: none;
tab1 has variable content, so it is not practical to set a fixed height or min-height
Setting display: flex; on article interferes with nav
Setting display: flex; also interferes with display: none;
nav can not be moved to outside article
Both tab2 & tab3 display with shorter height which results in unsightly resizing of the overall box
N.B. The HTML is used in a Firefox/Chrome Extension's Options page, and NOT a web page. Since Chrome uses Panels and Firefox uses Options page, Pixel based solutions might not work as expected. There might also be Firefox/Chrome specific solutions.
To have dynamic equal height elements without script, you could use CSS Flexbox.
Here I added a couple of input's and label's to do the actual tabbing, and an extra div as a wrapper for the section's.
By setting overflow: hidden on the article, give the div the size times amount of section's, one can simply slide it back and forth, sideways, to achieve your requirements.
Fiddle demo
Here done as a Stack snippet with a twist, animated the slide and, as commented, with 4 sections
article {
overflow: hidden;
}
article > input {
display: none;
}
article nav {
width: 100%;
background: lightgreen;
}
article nav label {
display: inline-block;
padding: 3px 10px;
}
article > div {
display: flex;
width: 400%;
transition: transform 1s; /* added to animate the slide */
}
article section {
width: 100%;
padding: 3px 10px;
box-sizing: border-box;
background: lightblue;
}
article input[id="tab1"]:checked ~ div {
transform: translateX(0);
}
article input[id="tab2"]:checked ~ div {
transform: translateX(-25%);
}
article input[id="tab3"]:checked ~ div {
transform: translateX(-50%);
}
article input[id="tab4"]:checked ~ div {
transform: translateX(-75%);
}
<article>
<!-- added inputs and labels for this demo -->
<input type="radio" name="radiotabs" id="tab1" checked>
<input type="radio" name="radiotabs" id="tab2">
<input type="radio" name="radiotabs" id="tab3">
<input type="radio" name="radiotabs" id="tab4">
<nav>
<label for="tab1">Tab 1</label>
<label for="tab2">Tab 2</label>
<label for="tab3">Tab 3</label>
<label for="tab4">Tab 4</label>
</nav>
<!-- this extra wapper is needed to solve this without script -->
<div>
<section id="stab1">
Section 1
</section>
<section id="stab2">
Section 2
<br>this has more content
<br>this has more content
<br>this has more content
</section>
<section id="stab3">
Section 3
</section>
<section id="stab4">
Section 4
</section>
</div>
</article>
You could do it easily with a bit of jquery like this:
$(document).ready(function() {
$(window).resize(function() {
$(".div1").height("auto");
$(".div2").height("auto");
$(".div3").height("auto");
var height = Math.max($(".div1").outerHeight(), $(".div2").outerHeight(), $(".div3").outerHeight());
$(".div1").height(height);
$(".div2").height(height);
$(".div3").height(height);
}).resize();
});
The variable height will be highest height of any of the 3 elements and then you apply it to all 3.
FIDDLE
I added the "resize" function to make it work if user resizes the window as the height may change while doing it.
Related
I am trying to create a general solution to a problem I encounter fairly often.
I am attempting to use the checkbox hack in tandem with a CSS grid in order to create a tabbed navigation menu that doesn't need to be modified when the HTML changes. If you run the code snippet, you'll see that you can add or remove any of the input/label/section trios and the CSS can just handle it.
What I am failing to accomplish is getting the second row to span all columns effectively filling the available space. I have come to understand that I am unable to get a row to span all columns unless I define an explicit grid. Unfortunately, defining a set number of columns defeats the whole purpose of what I am trying to do.
Working under the constraint that the HTML will always be input/label/section blocks in that order, is there any way to get that second row to span all columns without defining a set number of columns? I tried to get this to work using flexbox, but I couldn't get the columns right.
I am trying to get this with just CSS please, no javascript.
#Wrapper {
display: grid;
grid-auto-columns: 1fr;
grid-template-rows: 2em calc(100% - 2em);
height: 100%;
width: 100%;
}
#Wrapper section,
input[name=buttons] {
display: none
}
/*This doesn't work*/
#Wrapper section {
grid-column-start: 1;
grid-column-end: -1;
}
#Wrapper input[name=buttons]+label {
border-style: solid;
border-width: 1px;
cursor: pointer;
grid-row-start: 1;
grid-row-end: 2;
}
#Wrapper>input[name=buttons]:checked+label {
background-color: red;
}
#Wrapper>input[name=buttons]:checked+label+section {
display: block;
width: 100%;
}
<div id='Wrapper'>
<input type='radio' id='TabButton1' name='buttons' checked></input>
<label for='TabButton1'>SECTION 1</label>
<section>
This is some content 1
</section>
<input type='radio' id='TabButton2' name='buttons'></input>
<label for='TabButton2'>SECTION 2</label>
<section>
This is some content 2
</section>
<input type='radio' id='TabButton3' name='buttons'></input>
<label for='TabButton3'>SECTION 3</label>
<section>
This is some content 3
</section>
<input type='radio' id='TabButton4' name='buttons'></input>
<label for='TabButton4'>SECTION 4</label>
<section>
This is some content 4
</section>
<input type='radio' id='TabButton5' name='buttons'></input>
<label for='TabButton5'>SECTION 5</label>
<section>
This is some content 5
</section>
</div>
I got two DIVs that I switch visibility with, via two radio buttons.
I cant figure out how to use css transition to fade the content in and out when switching DIV. For example, have the div fade out to the left, while the other fades in from the right.
Second issue is, I tried to set the div to position:absolute, but the content below the two divs would then be hidden, i need the content below my two DIVS that I hide/show, to always be below. So i guess position absolute is a no go.
.div_one,
.div_two{
display:none !important;
}
#radio_one:checked ~ .div_one,
#radio_two:checked ~ .div_two{
display:block !important;
}
.div_one{
background-color:grey;
}
.div_two{
background-color:orange;
}
#below{
background-color:pink;
}
<input type="radio" name="tabs" id="radio_one" checked="checked"/>
<label for="radio_one" >01</label>
<input type="radio" name="tabs" id="radio_two" />
<label for="radio_two" class="">02</label>
<div class="div_one">
div one
</div>
<div class="div_two">
div two<br/><br/>
</div>
<div id="below">i need to be below the above block, regardless of their height.</div>
thanks in advance!
What you usually do in case you want to have an animation when one div slides to the side and another one slides in, is put them both in a parent div (usually referred to as the track) which is twice the width of its parent, and then use transform: translateX() to shift its location. It's also important to give the track overflow: hidden;. Now you don't need to give the slides an absolute position.
Regarding the track height, I added a JS snippet that would change the height according to the item displayed.
Example:
const track = document.getElementById('track');
const slides = document.querySelectorAll('#track > .slide');
const buttons = document.querySelectorAll('.radio_button');
buttons.forEach((button, idx) => {
button.addEventListener('click', () => {
let height = slides[idx].offsetHeight;
track.style.height = height + 'px';
});
});
* {
overflow: hidden;
}
#track {
width: 200%;
transition: all 0.3s ease;
overflow: hidden;
height: 1em;
}
.slide {
width: 50%;
display: inline-block;
float: left;
}
#radio_one:checked~#track {
transform: translateX(0%);
}
#radio_two:checked~#track {
transform: translateX(-50%);
}
#div_one {
background-color: grey;
}
#div_two {
background-color: orange;
}
#below {
background-color: pink;
}
<input type="radio" name="tabs" class="radio_button" id="radio_one" checked="checked" />
<label for="radio_one">01</label>
<input type="radio" name="tabs" class="radio_button" id="radio_two" />
<label for="radio_two" class="">02</label>
<div id="track">
<div class="slide" id="div_one">
div one
</div>
<div class="slide" id="div_two">
div two
<br/>
<br/>
</div>
</div>
<div id="below">i need to be below the above block, regardless of their height.</div>
I am trying to integrate purecss (purecss.io) into wordpress and i have problems setting grid boxes 100% height. I apply a gray background (odd/even nth-child css property) and it clearly shows the problem with variable content inside the boxes.
How do i set the boxes 100% height, so that i can apply background uniformly?
In the screenshot, i want the grid box showing search form to be 100% height so that entire background is gray.
<widgets class="pure-g">
<div id="search-2" class="pure-u-1 pure-u-md-1-2 l-box widget widget_search"><form role="search" method="get" id="searchform" class="searchform" action="http://localhost/wp/">
<div>
<label class="screen-reader-text" for="s">Search for:</label>
<input type="text" value="" name="s" id="s" />
<input type="submit" id="searchsubmit" value="Search" />
</div>
</form></div> <div id="recent-posts-2" class="pure-u-1 pure-u-md-1-2 l-box widget widget_recent_entries"> <h2>Recent Posts</h2> <ul>
<li>
WordPress themes are just being released today all over the World 1200 GMT
</li>
<li>
Hello world!
</li>
<li>
Markup: HTML Tags and Formatting
</li>
<li>
Markup: Image Alignment
</li>
<li>
Markup: Text Alignment
</li>
</ul>
</div>
</widgets>
I apply gray background color to odd widgets with this css code
/** Front page widgets ***/
.widget { font-size: 1.7vw; }
.gray { background: #eee; }
.widget img {
display:block;
margin: 20px;
}
.widget:nth-child(odd) { background: #eee }
.widget p { overflow:hidden; margin-left: 2em; display: block }
.widget h2 { margin:0; padding-bottom: 0.7em }
This is an excellent use case for flexbox. Just set the display property of the parent of the grid elements to flex, like so:
.pure-g {
display: flex;
}
And the heights of the grid elements will be normalized.
As others have suggested already, you might also be able to achieve similar results by setting the display properties of involved elements to their respective table counterparts, essentially turning your grid into a fake table.
Other than that there's no way to normalize column heights with CSS without taking (one of) the elements out the content flow, which may not be desired.
In CSS, height: 100% doesn't quite behave as one would expect. Any percentual height won't resolve to an actual height unless their direct parent has as explicit height declared, but since you have dynamic content height you cannot/should not set a static value.
You could work around this by using javascript to dynamically set the height of the parent to the height of the tallest child, thus making percentual heights work inside of it, but that's an entirely different question.
Here I've got a way to do this, first make those divs display: table-cell. This will make them go equal height. And for responsiveness of your website at lower mobile resolutions, you can use #media query to set the divs back to display: block
See the live example what I mean.
You will see both the divs at equal height due to display: table-cell, but when you will drag the left border of the Result window to make its width smaller then you will see at window width: 500px they break on next line. You can also fully control this behavior as you want.
#search-2, #recent-posts-2 { /* or you can simply use .widget here */
padding: 20px;
display: table-cell;
}
#media all and (max-width: 500px) {
#search-2, #recent-posts-2 {
display: block;
}
}
widget {
display: table;
}
#search-2, #recent-posts-2 {
display: table-cell;
}
Working fiddle
https://jsfiddle.net/bj1kqn6k/4/
This will Work,
HTML
<div class="pure-g hellodiv">
<div id="search-2" class="pure-u-1 pure-u-md-1-2 l-box widget widget_search"><form role="search" method="get" id="searchform" class="searchform" action="http://localhost/wp/">
<div>
<label class="screen-reader-text" for="s">Search for:</label>
<input type="text" value="" name="s" id="s" />
<input type="submit" id="searchsubmit" value="Search" />
</div>
</form>
</div>
<div id="recent-posts-2" class="pure-u-1 pure-u-md-1-2 l-box widget widget_recent_entries"> <h2>Recent Posts</h2> <ul>
<li>
WordPress themes are just being released today all over the World 1200 GMT
</li>
<li>
Hello world!
</li>
<li>
Markup: HTML Tags and Formatting
</li>
<li>
Markup: Image Alignment
</li>
<li>
Markup: Text Alignment
</li>
</ul>
</div>
</div>
CSS
html,body{height:100%;margin:0 auto;}
.hellodiv {
display: table;background-color:red;height:100%;
}
#search-2, #recent-posts-2 {
display: table-cell;
}
/** Front page widgets ***/
.widget { font-size: 1.7vw; }
.gray { background: #eee; }
.widget img {
display:block;
margin: 20px;
}
.widget:nth-child(odd) { background: #eee }
.widget p { overflow:hidden; margin-left: 2em; display: block }
.widget h2 { margin:0; padding-bottom: 0.7em }
Some times to have such a layout, you need absolute or fixed positioning, I would go for fixed, since the div will always remain full height:
.widget_search {
position:absolute;
top:0;
bottom:0;
width:15em;
}
This can be achieved with flex-box. https://jsfiddle.net/pt9q18j9/
there are two parts to flexbox, the container and the items in the container
set your container, in this case widgets to be display:flex;
widgets{
display: flex;
}
then the items you want to display side by side get the flex-basis property. setting a value of 1 on each means they will default to being the same size, if you set something like 1 for search and 2 for entries, entries would attempt to take up twice the space
.widget .widget_search {
flex-basis: 1;
}
.widget .widget_recent_entries {
flex-basis: 1;
}
this is a very good article on flex-box https://css-tricks.com/snippets/css/a-guide-to-flexbox/
Add below custom css in your css.
.pure-g {
display: table;
table-layout: fixed;
}
.widget {
font-size: 1.7vw;
vertical-align: middle;
}
I am setting up a FAQ page. On the page I have a div, of class=”faq_container”, with 6 child divs arranged in a 3×3 grid that contain the faq questions. So basically I have 6 clickable boxes.
Each question, when clicked, will reveal its answer hiding the all the questions but maintained within the faq_container div. There would be a close link below the answer to hide the answer and take you back to the questions.
I know this is probably pretty simple. I’m hoping someone can help me out.
Thanks!
While you've accepted a JavaScript solution, there are (at least) two ways that this can be achieved with CSS alone, the first using CSS :target pseudo-classes, and the second using input, and label, elements.
The first, assuming HTML similar to the following:
<div id="faq_container">
<ol>
<li id="faq1">
<h2>Question 1</h2>
<div>
<p>Text, relating to question one.</p> <a class="close" href="#hide">close</a>
<!-- the above link doesn't link to anything, just changes the hash whcih stops the ':target' pseudo-class matching the the current 'div' element -->
</div>
</li>
<!-- subsequent elements follow the above structure, stripped for brevity -->
</ol>
</div>
With the following CSS (albeit there's more CSS in the demo, since I've stripped out some of the purely aesthetic stuff here, for brevity, as above):
li {
/* some stripped out aesthetics */
position: relative; /* used to position the '.close' links */
}
li div {
height: 0; /* to allow for animation of the height 'none' to 'block' can't animate */
overflow: hidden;
/* all vendor prefixes removed for brevity, here and later */
transition: all 0.5s linear; /* animates to the default properties, from other 'states' */
}
/* li:target matches when the 'id' of the 'li' is equal to the hash/fragment-identifier in the URL */
li:target div {
height: 4em; /* to allow for animation (this is the awkward part of using pure CSS) */
transition: all 0.5s linear; /* transitions to the 'selected' state (when the user clicks a link in the 'h2' element) */
}
li a:link, li a:visited {
/* aesthetics removed */
}
/* styling the 'interactive' states (:hover, :active, :focus), and the 'selected' state using 'li:target h2 a' */
li a:hover, li a:active, li a:focus, li:target h2 a {
font-weight: bold;
text-decoration: underline;
}
a.close {
/* styling the '.close' link, so it's invisible in the 'non-selected' state */
position: absolute;
opacity: 0;
width: 0;
overflow: hidden;
transition: all 0.65s linear;
}
/* styling the '.close' link, so it's only visible when the question is 'selected' */
li:target a.close {
opacity: 1;
width: 4em;
transition: all 0.65s linear;
}
JS Fiddle demo.
The second approach uses label and input elements (type="radio" if only one question can be visible at a time, type="checkbox" if multiple elements can be visible), based on the following HTML:
<input id="close" name="question" type="radio" />
<div id="faq_container">
<ol>
<li>
<input id="faq1" type="radio" name="question" />
<h2><label for="faq1">Question 1</label></h2>
<div>
<div>
<p>Text, relating to question one.</p>
<label for="close">Close</label>
<!-- the above 'label' closes the question, by referring to an
'input' of the same name (different 'id'), taking advantage
of the fact that only one radio-'input' of a given name can
be checked (this 'input' is just before the ancestor 'ol') -->
</div>
</div>
</li>
<!-- subsequent elements follow the above structure, stripped for brevity -->
</ol>
</div>
And the following CSS (as before, aesthetics removed for brevity):
/* you could, instead, use a class-name to identify the relevant radio-inputs */
input[type=radio] {
/* using 'display: none' (apparently) in some browsers prevents
interactivity, so we fake it, by hiding: */
position: absolute;
opacity: 0;
left: -1000px;
}
/* styling the 'div' that's the adjacent-sibling of an 'h2' which is an
adjacent-sibling of an 'input' all of which are descendants of a 'div' */
div input + h2 + div {
height: 0; /* to allow for animating with transitions */
overflow: hidden;
/* vendor prefixes, again, stripped out */
transition: all 0.5s linear;
}
/* using 'input:checked + h2 + div' causes problems in Chrome, check the references;
so we're styling (respectively) a 'div' which is an adjacent sibling to an 'h2'
which is an adjacent-sibling of a checked 'input', and/or
a 'div' which is a general-sibling of a checked 'input' (in both cases these are
all descendants of another 'div' element) */
div input:checked + h2 + div,
div input:checked ~ div {
height: 4em; /* to allow for animating with transitions */
overflow-y: auto; /* a personal preference, but allows for
scrolling if the height is insufficient
though it can be a little ugly, with a flicker */
transition: all 0.5s linear;
}
JS Fiddle demo.
The same approach can be used with checkboxes, which allows the label to toggle the display of the relevant question, and makes the close links/labels pointless, HTML:
<div id="faq_container">
<ol>
<li>
<input id="faq1" type="checkbox" name="question" />
<h2><label for="faq1">Question 1</label></h2>
<div>
<div>
<p>Text, relating to question one.</p>
</div>
</div>
</li>
<!-- subsequent elements follow the above structure, stripped for brevity -->
</ol>
</div>
And CSS (precisely as the preceding example, but changed input[type=radio] to input[type=checkbox]):
/* duplicated, and aesthetic, CSS removed for brevity */
input[type=checkbox] {
position: absolute;
opacity: 0;
left: -1000px;
}
JS Fiddle demo.
References:
:target pseudo-selector.
Adjacent-sibling (+) combinator.
General-sibling (~) combinator.
Problems using chained adjacent-sibling combinators, particularly in Chrome: "Why does the general-sibling combinator allow toggling pseudo-element's content, but not the adjacent-sibling?"
If a jQuery solution is allowed, here is a quick mock-up.
$(".wrapper").click(function(){
$(this).children(".answer").toggle();
$(".wrapper").not(this).toggle();
$(".faq_container").toggleClass("active");
});
The simplest means of achieving what you're asking for comes down to changing the "class" attribute value of these DIV elements when their respective OnClick events are fired. For that, you'll need to use a scripting engine of some kind, and that is likely going to be JavaScript unless you want a post back, in which case you can just handle it in the code behind of the page. JQuery, as others have mentioned, is a good choice, but comes with some overhead.
The way this site works is that you post what you've tried so far, and what results you're getting. I get the impression that you haven't tried anything, so I would suggest that you do some searching on this site or your web search engine of choice for a string like "javascript change css class onclick" and see where that leads you.
Without more specifics on your exact use case and environment, you are unlikely to get a "here, copy and paste this code into your page" type of answer.
[EDIT] Never mind. I always underestimate the compulsion of developers to begin writing code before knowing any constraints. Enjoy your copypasta.
You should use this kind of structure :
$('.question').on('click', function(ev) {
ev.preventDefault();
$(this).find('.answer').show();
});
$('.close').on('click', function(ev) {
ev.preventDefault();
ev.stopPropagation();
var dismiss = $(this).data('dismiss');
$(this).closest('.'+dismiss).hide();
});
.faq {
position: relative;
width: 600px;
}
.question {
height: 178px; width: 178px;
margin: 5px;
padding: 5px;
border: 1px solid black;
background: #efefef;
float: left;
cursor: pointer;
}
.answer {
position: absolute;
top: 0; left: 0;
height: 578px; width: 578px;
margin: 5px;
padding: 5px;
border: 1px solid black;
background: #bebebe;
cursor: default;
display: none;
}
a.close {
position: absolute;
top: 5px; right: 5px;
display: block;
height: 20px; width: 20px;
color: black;
border: 1px solid black;
line-height: 20px;
text-align: center;
text-decoration: none;
}
a.close:hover {
background: #9f9f9f;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<section class="faq">
<article class="question">Question 1 ?
<div class="answer">
Answer 1 !
×
</div>
</article>
<article class="question">Question 2 ?
<div class="answer">
Answer 2 !
×
</div>
</article>
<article class="question">Question 3 ?
<div class="answer">
Answer 3 !
×
</div>
</article>
<article class="question">Question 4 ?
<div class="answer">
Answer 4 !
×
</div>
</article>
<article class="question">Question 5 ?
<div class="answer">
Answer 5 !
×
</div>
</article>
<article class="question">Question 6 ?
<div class="answer">
Answer 6 !
×
</div>
</article>
<article class="question">Question 7 ?
<div class="answer">
Answer 7 !
×
</div>
</article>
<article class="question">Question 8 ?
<div class="answer">
Answer 8 !
×
</div>
</article>
<article class="question">Question 9 ?
<div class="answer">
Answer 9 !
×
</div>
</article>
</section>
For the CSS, you'll need to mix float: left for your 3*3 pattern, and position: absolute for each answer.
I'm trying to let an <input type="text"> (henceforth referred to as “textbox”) fill a parent container by settings its width to 100%. This works until I give the textbox a padding. This is then added to the content width and the input field overflows. Notice that in Firefox this only happens when rendering the content as standards compliant. In quirks mode, another box model seems to apply.
Here's a minimal code to reproduce the behaviour in all modern browsers.
#x {
background: salmon;
padding: 1em;
}
#y, input {
background: red;
padding: 0 20px;
width: 100%;
}
<div id="x">
<div id="y">x</div>
<input type="text"/>
</div>
My question: How do I get the textbox to fit the container?
Notice: for the <div id="y">, this is straightforward: simply set width: auto. However, if I try to do this for the textbox, the effect is different and the textbox takes its default row count as width (even if I set display: block for the textbox).
EDIT: David's solution would of course work. However, I do not want to modify the HTML – I do especially not want to add dummy elements with no semantic functionality. This is a typical case of divitis that I want to avoid at all cost. This can only be a last-resort hack.
With CSS3 you can use the box-sizing property on your inputs to standardise their box models.
Something like this would enable you to add padding and have 100% width:
input[type="text"] {
-webkit-box-sizing: border-box; // Safari/Chrome, other WebKit
-moz-box-sizing: border-box; // Firefox, other Gecko
box-sizing: border-box; // Opera/IE 8+
}
Unfortunately this won't work for IE6/7 but the rest are fine (Compatibility List), so if you need to support these browsers your best bet would be Davids solution.
If you'd like to read more check out this brilliant article by Chris Coyier.
Hope this helps!
You can surround the textbox with a <div> and give that <div> padding: 0 20px. Your problem is that the 100% width does not include any padding or margin values; these values are added on top of the 100% width, thus the overflow.
Because of the way the Box-Modell is defined and implemented I don't think there is a css-only solution to this problem. (Apart from what Matthew described: using percentage for the padding as well, e.g. width: 94%; padding: 0 3%;)
You could however build some Javascript-Code to calculate the width dynmically on page-load... hm, and that value would of course also have to be updated every time the browserwindow is resized.
Interesting by-product of some testing I've done: Firefox does set the width of an input field to 100% if additionally to width: 100%; you also set max-width to 100%. This doesn't work in Opera 9.5 or IE 7 though (haven't tested older versions).
How do I get the textbox to fit the container in 2019?
Just use display: flex;
#x {
background: salmon;
padding: 1em;
display: flex;
flex-wrap: wrap;
}
#y, input {
background: red;
padding: 0 20px;
width: 100%;
}
<div id="x">
<div id="y">x</div>
<input type="text"/>
</div>
This is unfortunately not possible with pure CSS; HTML or Javascript modifications are necessary for any non-trivial flexible-but-constrained UI behavior. CSS3 columns will help in this regard somewhat, but not in scenarios like yours.
David's solution is the cleanest. It's not really a case of divitis -- you're not adding a bunch of divs unnecessarily, or giving them classnames like "p" and "h1". It's serving a specific purpose, and the nice thing in this case is that it's also an extensible solution -- e.g. you can then add rounded corners at any time without adding anything further. Accessibility also isn't affected, as they're empty divs.
Fwiw, here's how I implement all of my textboxes:
<div class="textbox" id="username">
<div class="before"></div>
<div class="during">
<input type="text" value="" />
</div>
<div class="after"></div>
</div>
You're then free to use CSS to add rounded corners, add padding like in your case, etc., but you also don't have to -- you're free to hide those side divs altogether and have just a regular input textbox.
Other solutions are to use tables, e.g. Amazon uses tables in order to get flexible-but-constrained layout, or to use Javascript to tweak the sizes and update them on window resizes, e.g. Google Docs, Maps, etc. all do this.
Anyway, my two cents: don't let idealism get in the way of practicality in cases like this. :) David's solution works and hardly clutters up HTML at all (and in fact, using semantic classnames like "before" and "after" is still very clean imo).
This behavior is caused by the different interpretations of the box model. The correct box model states that the width applies only to the content and padding and margin add on to it. So therefore your are getting 100% plus a 20px right and left padding equaling 100%+40px as the total width. The original IE box model, also known as quirks mode, includes padding and margin in the width. So the width of your content would be 100% - 40px in this case. This is why you see two different behaviors. As far as I know there is no solution for this there is however a work around by setting the width to say 98% and the padding to 1% on each side.
#Domenic this does not work. width auto does nothing more then the default behavior of that element because the initial value of width is auto ( see page 164, Cascading Style Sheets Level 2 Revision 1 Specification). Assigning a display of type block does not work either, this simply tell the browser to use a block box when displaying the element and does not assign a default behavior of taking as much space as possible like a div does ( see page 121, Cascading Style Sheets Level 2 Revision 1 Specification). That behavior is handled by the visual user agent not CSS or HTML definition.
i believe you can counter the overflow with a negative margin. ie
margin: -1em;
The default padding and border will prevent your textbox from truly being 100%, so first you have to set them to 0:
input {
background: red;
padding: 0;
width: 100%;
border: 0; //use 0 instead of "none" for ie7
}
Then, put your border and any padding or margin you want in a div around the textbox:
.text-box {
padding: 0 20px;
border: solid 1px #000000;
}
<body>
<div id="x">
<div id="y">x</div>
<div class="text-box"><input type="text"/></div>
</div>
</body>
This should allow your textbox to be expandable and the exact size you want without javascript.
To make the input fill up width of parent, there're 3 attributes to set: width: 100%, margin-left: 0, margin-right: 0.
I just guess zero margin setting can help, and I had tried it, however I don't know why margin (left and right; of course top and bottom margins don't affect here) should to be zero to make it works. :-)
input {
width: 100%;
margin-left: 0;
margin-right: 0;
}
Note: You may need to set box-sizing to border-box to make sure the padding don't affect the result.
I use to solve this with CSS-only tables. A little bit long example but
important for all who wants to make entry screens for large amount of fields
for databases...
// GH
// NO JAVA !!! ;-)
html {
height: 100%;
}
body {
position: fixed;
margin: 0px;
padding: 0px;
border: 2px solid #FF0000;
width: calc(100% - 4px);
/* Demonstrate how form can fill body */
min-height: calc(100% - 120px);
margin-top: 60px;
margin-bottom: 60px;
}
/* Example how to make a data entry form */
.rx-form {
display: table;
table-layout: fixed;
border: 1px solid #0000FF;
width: 100%;
border-collapse: separate;
border-spacing: 5px;
}
.rx-caption {
display: table-caption;
border: 1px solid #000000;
text-align: center;
padding: 10px;
margin: 10px;
width: calc(100% - 40px);
font-size: 2.5em;
}
.rx-row {
display: table-row;
/* To make frame on rows. Rows have no border... ? */
box-shadow: 0px 0px 0px 1px rgb(0, 0, 0);
}
.rx-cell {
display: table-cell;
margin: 0px;
padding: 4px;
border: 1px solid #FF0000;
}
.rx-cell label {
float: left;
border: 1px solid #00FF00;
width: 110px;
padding: 4px;
font-size: 1em;
text-align: right;
font-family: Arial, Helvetica, sans-serif;
overflow: hidden;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.rx-cell label:after {
content: " :";
}
.rx-cell input[type='text'] {
float: right;
border: 1px solid #FF00FF;
padding: 4px;
background-color: #eee;
border-radius: 0px;
font-family: Arial, Helvetica, sans-serif;
font-size: 1em;
/* Fill the cell - but subtract the label width - and litte more... */
width: calc(100% - 130px);
overflow: hidden;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
input[type='submit'] {
font-size: 1.3em;
}
<html>
<meta charset="UTF-8">
<body>
<!--
G Hasse, gorhas at raditex dot nu
This example have a lot of frames so we
can experiment with padding and margins.
-->
<form>
<div class='rx-form'>
<div class='rx-caption'>
Caption
</div>
<!-- First row of entry -->
<div class='rx-row'>
<div class='rx-cell'>
<label for="input11">Label 1-1</label>
<input type="text" name="input11" id="input11" value="Some latin text here. And if it is very long it will get ellipsis" />
</div>
<div class='rx-cell'>
<label for="input12">Label 1-2</label>
<input type="text" name="input12" id="input12" value="The content of input 2" />
</div>
<div class='rx-cell'>
<label for="input13">Label 1-3</label>
<input type="text" name="input13" id="input13" value="Content 3" />
</div>
<div class='rx-cell'>
<label for="input14">Label 1-4</label>
<input type="text" name="input14" id="input14" value="Content 4" />
</div>
</div>
<!-- Next row of entry -->
<div class='rx-row'>
<div class='rx-cell'>
<label for="input21">Label 2-1</label>
<input type="text" name="input21" id="input21" value="Content 2-1">
</div>
<div class='rx-cell'>
<label for="input22">Label 2-2</label>
<input type="text" name="input22" id="input22" value="Content 2-2">
</div>
<div class='rx-cell'>
<label for="input23">Label 2-3</label>
<input type="text" name="input23" id="input23" value="Content 2-3">
</div>
</div>
<!-- Next row of entry -->
<div class='rx-row'>
<div class='rx-cell'>
<label for="input21">Label 2-1</label>
<input type="text" name="input21" id="input21" value="Content 2-1">
</div>
<div class='rx-cell'>
<label for="input22">Label 2-2</label>
<input type="text" name="input22" id="input22" value="Content 2-2">
</div>
<div class='rx-cell'>
<label for="input23">Label 2-3</label>
<input type="text" name="input23" id="input23" value="Content 2-3">
</div>
</div>
<!-- And some text in cells -->
<div class='rx-row'>
<div class='rx-cell'>
<div>Cell content</div>
</div>
<div class='rx-cell'>
<span>Cell content</span>
</div>
</div>
<!-- And we place the submit buttons in a cell -->
<div class='rx-row'>
<div class='rx-cell'>
<input type="submit" name="submit1" value="submit1" />
<input type="submit" name="submit2" value="submit2" />
</div>
</div>
<!-- End of form -->
</div>
</form>
</body>
</html>