I am trying to achieve a layout in which input fields appear in a column. When the column exceeds the height of its container, it must wrap horizontally.
I have achieved this layout using flexbox, but flexbox (and more specifically the flex-wrap property) isn't widely enough supported. In my case, I need to support modern web browsers and at least IE9+
Additionally, the form content is generated by Ember.js along the lines of this method. The model that is bound to the form changes, which means the number of input fields is dynamic.
How can I achieve this layout more compatibly?
Just updated your Fiddle a little: http://jsfiddle.net/43k5s/6/
.menu-form {
background-color: lightgray;
padding: 1em 1.5em;
}
.menu-form:before, .menu-form:after {
content: "\0020";
display: block;
height: 0;
visibility: hidden;
}
.menu-form:after {
clear: both;
}
.menu-form {
zoom: 1;
}
.menu-form div {
width: 33%;
float: left;
}
.menu-form div label {
display: block;
}
Using floats and clearfix this should work in all major browsers (even older IE). You might also work with fixed widths or media queries to change the number of columns.
Related
I have three containers (div), the third div has a set width but I need the other two to be responsive. Current html setup:
<div id="page-type">
<div id="type-container">
<div>
<p id="type-title">Events</p>
</div>
</div>
<div class="type-options">
</div>
<div id="type-back">
Back to Explore
</div>
</div>
Current css:
#page-type {
float: left;
width: 100%;
background: #D2D3D5;
height: 60px;
}
#type-container {
float: left;
width: auto;
}
#type-options {
height: 60px;
width: auto;
overflow: hidden;
}
#type-back {
border-left: 1px #BDBEC1 solid;
float: right;
width: 160px;
}
I can get type-container and type-options to be on the same line and responsive but I can't keep type-back on the same line.
visual example:
----- EDIT -----
To clarify more:
type-container adjusts to fit it's content
type-back is a set width
type-option fills in the space between type-container and type-back regardless of content
type-containerand type-options fill up the whole row pushing type-back to the next line. I need type-back to stay to the right of the line while the other two are responsive.
Put a wrapper around your first two columns and then you can use CSS3's calc().
#wrapper {
width: calc(100% - 161px); /* extra px for 1px border */
float: left;
}
Demo here
IE8 Workaround - Use border-box:
#wrapper {
margin-right: -161px;
padding-right: 161px;
width: 100%;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
IE8 Demo
In CSS3 you can use calc(X% - 160px) to reduce the width of a percentage based container by a number of pixels.
A quick example could be: http://jsfiddle.net/e3vC4/
There isn't a need to use calc for this, even though its a nice feature to have (+1) — sadly its support is still patchy in places and despite much research it's still difficult to say exactly which browser versions will work as expected (fine if you assume all modern browser users auto-upgrade however).
Depending on what your prerequisites are, you have two other options that I'm aware of:
1. Position absolute the last column
This is a simple solution, however something to be wary of is that certain older mobile devices may treat position absolute in odd ways.
In order to get this to work, all you need to do is place position: relative on your container, and position: absolute; right: 0; top: 0; on your third column... and to keep the centering of your central column correct, add margin-right: 161px.
Pos. Abs. example on JSFiddle
CSS ~ markup is as per your example
#page-type {
display: block;
position: relative; /* added */
width: 100%;
background: #D2D3D5;
height: 60px;
overflow: hidden;
}
#type-container {
display: block;
float: left;
text-align: center;
}
#type-options {
display: block;
height: 100%;
text-align: center;
overflow: hidden;
margin-right: 161px; /* added */
}
#type-back {
display: block;
position: absolute; /* added */
right: 0; /* added */
top: 0; /* added */
border-left: 1px #BDBEC1 solid;
width: 160px;
height: 100%;
}
2. Float right, and/or left, before sibling without hasLayout / shrinkwrap
This works on the basis that a floated element takes up space in the document, and a block element, by default, auto-expands to fill the remaining area that it can — as long as it hasn't been forced to rigidly define its edges with the likes of float, overflow or other hasLayout or shrinkwrap tricks.
This option is only open to you if you can re-arrange your DOM ordering i.e. place #type-back before #type-options. This won't affect the visual order, but it makes a big difference to how the layout is calculated, and is one of the reasons why you were encountering problems with your attempts. You need to have the floated elements in place before leaving the other elements to calculate their dimensions.
Float example on JSFiddle
NOTE: Changing the order of DOM elements can be of benefit, but it can also be a hindrance; it all depends on what the markup is, and who will be viewing it. For example, sometimes having actionable links higher up the DOM can be useful to tabbing and screen-reader users, but the opposite can also be true depending on the context.
MARKUP ~ note the rearranged DOM order
<div id="page-type">
<div id="type-container">
<p id="type-title">Events</p>
</div>
<div id="type-back">
<p>Back to Explore</p>
</div>
<div id="type-options">
<p>Options</p>
</div>
</div>
CSS
#page-type {
display: block;
width: 100%;
background: #D2D3D5;
height: 60px;
overflow: hidden;
}
#type-container {
display: block;
float: left;
text-align: center;
}
#type-options {
display: block;
height: 100%;
text-align: center;
overflow: hidden;
}
#type-back {
float: right;
border-left: 1px #BDBEC1 solid;
width: 160px;
height: 100%;
}
NOTE: It should be stated this version does break on to the next line when "responsed" down to a very minimal size. However, I tend to prefer to design items to disappear when space is tight, and this method lends well to that thinking.
Summary
These are just two other possible options. If you are developing for a progressive client, or yourself, then I personally would stick with the calc method. It's easier to work out what is going on, and far easier for a future developer to change.
However, sometimes often frequently all the blasted time clients want to support the widest range of devices possible (without investing the extra time and money that would be required), and in this instance you are better off with an alternative method (one that isn't going to randomly break on a manager's less than contemporary laptop, running IE 7.5? or 8.33333??? or even Netscape 4.7¿).
Unless of course, you have any leeway to fight for using the more progressive approach, which does seem to be getting easier of late.
I sat down with the designer for more clarification and to discuss alternate solutions. I'm making the third did responsive as well allowing me to use two containers: one holds page-type and type-options set to x% and another holds type-back set to y%. Doing this allows me to keep all elements responsive.
I am trying to setup a form such that:
All inputs will be horizontally aligned, even when they have no label.
Inputs will be vertically aligned within their row for when the label wraps.
The inputs will stretch to fill the remaining space (or squished)
The submit button will fill an entire row.
I have achieved the first and fourth requirements but I am having trouble with making the inputs fill the row and be vertically aligned.
Here's my progress so far:
http://jsbin.com/kozozabo/3/edit?html,css,output
The LESS:
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
#narrow-form {
width: 300px;
overflow: hidden;
padding-right: 0.5em;
}
#wide-form {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin-left: 300px;
}
.row {
#label-width: 100px;
width: 100%;
overflow: hidden;
label {
width: #label-width;
float: left;
display: inline-block;
}
.no-label {
margin-left: #label-width;
}
input, select {
/* Trying to make these aligned to the right of
* their respective labels filling any remaining
* width.
*/
display: inline-block;
}
button {
width: 100%;
}
}
I tried giving the inputs absolute positioning with a left margin of the same width of the label but that didn't work.
Okay I have come up with a solution that I am happy with. It does involve some table abuse unfortunately.
I have only tested this in Chromium.
http://jsbin.com/kozozabo/5/edit?output
I set the form to display: table, each .row to display: table-row and the labels, inputs, selects and buttons to display: table-cell.
This made everything line up and fill all available space.
I then added two new classes intended to be affixes to the .row class, this is where the real table abuse begins.
.no-label - With the intent of "skipping" the first psuedo-cell. To accomplish this I defined it as such:
.no-label:before {
content: "";
display: table-cell;
}
Essentially inserting a hidden cell, forcing the subsequent inputs to be in the second column.
.full-width - With the intent of making it's contents the full width of the "table". To accomplish this I defined it as such:
.full-width {
display: table-caption;
caption-side: bottom;
}
A table caption spans the entire width of the table. I know I am only going to do this to the button so I forced it to be at the bottom with caption-side.
It would have been better to just define the DOM as a table but I didn't want to reprogram the javascript that was setting up this form. I always wouldn't get to of played with css, all be it in a menacing manner.
I'm trying to create some evenly spaced columns (an ol), with the columns themselves being fixed width.
So far, I've managed to achieve the desired effect by using table layout, and nesting an additional element inside the list item.
HTML:
<ol>
<li><div></div></li>
<li><div></div></li>
<li><div></div></li>
<li><div></div></li>
<li><div></div></li>
</ol>
CSS:
ol {
display: table;
width: 100%;
}
li {
display: table-cell;
}
div {
margin: 0 auto;
width: 100px;
height: 250px;
}
This works great, but has the following 2 shortcomings:
As you can see in the demo, the first & last columns don't line up flush with the parent's outer edges.
This can't really be used responsively. The only thing you can do at smaller widths is stack them, but I'd like to split them (2 or 3 per row).
Is what I'm after even possible in CSS alone? I know there are a plethora of ways to accomplish this in JS, but I'm after a CSS-only solution.
P.S. I don't care about IE7-, but I do need to support IE8. CSS3 selectors are OK though, since I'm anyhow using selectivizr in the project (I know that's JS ;-)).
It seems appropriate for you to recycle "how to *really* justify a horizontal menu". Basically the behaviour you're describing is that of inline-block elements of identical width having text-align:justify applied:
ol {
/*force the desired behaviour*/
text-align: justify;
/*remove the minimum gap between columns caused by whitespace*/
font-size: 0;
}
li {
/*make text-align property applicable*/
display: inline;
}
/*force "justify" alignment that requires text to be at least over 2 lines*/
ol:after {
content: "";
display: inline-block;
position: relative;
width: 100%;
height: 0;
}
div {
display: inline-block;
width: 100px;
height: 250px;
}
Working fiddle.
NB: you may have to re-apply desired font-size and text-align to descendants of ol depending on the reset you're using (i.e. to prevent these properties from being inherited)
Ok my first thought would be to use media queries to gain a responsive approach for how many you want to show per row on differing screen sizes and my second would be to use
box-sizing:border-box;
-moz-box-sizing:border-box;
-webkit-box-sizing:border-box;
this will stop the paddings you may put in later adding onto the box model size.
Hope this is close to what you are after.
I have a server-side component that generates a fluid layout "toolbar" using DIV without fixed width, generating many A inside it.
Then I need customize that layout to make all A tags auto fit to the parent width. But the number of children is variable and the parent's width isn't known (it auto fits itself to the window).
I made some tests with this Fiddle: http://jsfiddle.net/ErickPetru/6nSEj/1/
But I can't find a way to make it dynamic (uncomment the last A tag to see how it ins't working, lol).
I can't change the server-side sources to gerenate HTML with fixed width. And I really would like to solve it only with CSS if there is any way, even that with JavaScript I could achieve that result.
How can I make all the children auto-fit itself to the parent's width independently of the number of children?
You can use display: table-cell:
See: http://jsfiddle.net/6nSEj/12/ (or with 5 children)
This won't work in IE7 because that browser simply doesn't support display: table and friends.
div.parent {
..
width: 100%;
display: table;
table-layout: fixed;
}
div.parent a {
..
display: table-cell;
}
This is already a pretty old question. Although the answers given attended well at the time, nowadays the Flexible Box Layout offers the same result with much more simplicity, with good support in all modern browsers. I strongly recommend it!
/* Important parts */
.parent {
display: flex;
}
.parent a {
flex: 1;
}
/* Decoration */
.parent {
padding: 8px;
border: 1px solid #ccc;
background: #ededed;
}
.parent a {
line-height: 26px;
text-align: center;
text-decoration: none;
border: 1px solid #ccc;
background: #dbdbdb;
color: #111;
}
<div class="parent">
Some
Other
Any
</div>
<br>
<div class="parent">
Some
Other
Any
One More
Last
</div>
For now many use jQuery as a solution to this problem. All you need is one line. This is from your fiddle.
$("div.parent a").css("width", (($("div.parent").width() / $("div.parent a").length ) -2) + "px");
No matter what I set them to my DIVs I use for buttons don't resize. I'm uploading the correct file, and it has the change on the server, but nothing is happening no matter how much I refresh. I'll delete the URL so this can't be used as advertising once I get an answer.
[removed url]
The issue here is that you're trying to resize inline elements, which cannot be explicitly controlled. In order to set the height and width of the element, you need to set it's display mode to "block" and use float to align the elements horizontally.
div .button {
display: block;
-moz-border-radius: 25px;
-webkit-border-radius: 25px;
border: 3px double #F1A631;
background-color: #FCFF68;
float: left;
width: 150px;
height: 30px;
}
Also, you'll need to rearrange your DIVs in the reverse order you'd like them to be displayed left-to-right. There is display property in CSS2 called "inline-block" which is designed to correct this, but it's not universally supported.
In CSS, elements with display: inline cannot have width or height applied to them. You need display: inline-block for that. IE will incorrectly convert any inline element to inline-block if you give them a width or height. Fortunatley, since the release of Firefox 3 you can use inline-block with only minimal hacking.
no Firefox 2 compatibility:
.ib { display: inline-block; zoom: 1; *display: inline; }
Example HTML
<div class="ib button">My button</div>
Firefox 2 compatibilty
.ib{ display: -moz-inline-stack; display: inline-block; zoom: 1; *display: inline; }
.button { display: block; }
Example HTML
<div class="ib"><div class="button">My button</div></div>
In your .button implementation you would need to remove the display: inline portion.