Here's a fantastic CSS menu:
The only disadvantage its not stretched to 100%... if it has 2 elements, it should be 50%/50%, if 4 items then 25%/25%/25%/25% just like they were table cells. How to do that? I'm new to CSS.
Use display: table/table-cell (for modern browsers and IE8+) and display-table.htc (for IE6/7).
Modify its width as 100% will make the menu span to full width.
#myfantasticmenu { width: 100%; }
I simulated the change with firebug and the needed Style defination was
#nav {
overflow: hidden; /* To clear the div */
width: 100%;
}
And about the part, where you need 50/50 for two and 25 each when the item are 4, you will require some javascript to do so.
If you consider using jQuery then it will something like
childs= $("#myfantasticmenu").children('a'); //grab the list items
childs.css('width', (100/childs.length)+%);
If avoiding scripting is your MAJOR target, then bring tables into the games, they automatically do the behavior you need.
Related
I would like to use media queries to resize elements based on the size of a div element they are in. I cannot use the screen size as the div is just used like a widget within the webpage, and its size can vary.
Yes, CSS Container Queries are what you're looking for. The CSS Containment Module is the specification that details this feature.
You can read more about the decade of work, including proposals, proofs-of-concept, discussions and other contributions by the broader web developer community here! For more details on how such a feature might work and be used, check out Miriam Suzanne's extensive explainer.
Currently only Chromium 105+ supports Container queries out of the box, though Safari 16 will include support as well. Hopefully it won't be much longer before we see a robust cross-browser implementation of such a system. It's been a grueling wait, but I'm glad that it's no longer something we simply have to accept as an insurmountable limitation of CSS due to cyclic dependencies or infinite loops or what have you (these are still a potential issue in some aspects of the proposed design, but I have faith that the CSSWG will find a way).
Media queries aren't designed to work based on elements in a page. They are designed to work based on devices or media types (hence why they are called media queries). width, height, and other dimension-based media features all refer to the dimensions of either the viewport or the device's screen in screen-based media. They cannot be used to refer to a certain element on a page.
If you need to apply styles depending on the size of a certain div element on your page, you'll have to use JavaScript to observe changes in the size of that div element instead of media queries.
Alternatively, with more modern layout techniques introduced since the original publication of this answer such as flexbox and standards such as custom properties, you may not need media or element queries after all. Djave provides an example.
I've just created a javascript shim to achieve this goal. Take a look if you want, it's a proof-of-concept, but take care: it's a early version and still needs some work.
https://github.com/marcj/css-element-queries
From a layout perspective, it is possible using modern techniques.
Its made up (I believe) by Heydon Pickering. He details the process here: http://www.heydonworks.com/article/the-flexbox-holy-albatross
Chris Coyier picks it up and works through a demo of it here: https://css-tricks.com/putting-the-flexbox-albatross-to-real-use/
To restate the issue, below we see 3 of the same component, each made up of three orange divs labelled a, b and c.
The second two's blocks display vertically, because they are limited on horizontal room, while the top components 3 blocks are laid out horizontally.
It uses the flex-basis CSS property and CSS Variables to create this effect.
.panel{
display: flex;
flex-wrap: wrap;
border: 1px solid #f00;
$breakpoint: 600px;
--multiplier: calc( #{$breakpoint} - 100%);
.element{
min-width: 33%;
max-width: 100%;
flex-grow: 1;
flex-basis: calc( var(--multiplier) * 999 );
}
}
Demo
Heydon's article is 1000 words explaining it in detail, and I'd highly recommend reading it.
Update 2021/22
As mentioned in other answers, container queries are coming. There is a full spec for it, and its usage is detailed on MDN:
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries
and there is a polyfill to get browsers that don't yet support it up to speed:
https://github.com/GoogleChromeLabs/container-query-polyfill
There is a nice little overview video of it here:
https://www.youtube.com/watch?v=gCNMyYr7F6w
This has now shipped to Chrome (05 September 2022)
https://caniuse.com/css-container-queries
A Media Query inside of an iframe can function as an element query. I've successfully implement this. The idea came from a recent post about Responsive Ads by Zurb. No Javascript!
This is currently not possible with CSS alone as #BoltClock wrote in the accepted answer, but you can work around that by using JavaScript.
I created a container query (aka element query) polyfill to solve this kind of issue. It works a bit different than other scripts, so you don’t have to edit the HTML code of your elements. All you have to do is include the script and use it in your CSS like so:
.element:container(width > 99px) {
/* If its container is at least 100px wide */
}
https://github.com/ausi/cq-prolyfill
I ran into the same problem a couple of years ago and funded the development of a plugin to help me in my work. I've released the plugin as open-source so others can benefit from it as well, and you can grab it on Github: https://github.com/eqcss/eqcss
There are a few ways we could apply different responsive styles based on what we can know about an element on the page. Here are a few element queries that the EQCSS plugin will let you write in CSS:
#element 'div' and (condition) {
$this {
/* Do something to the 'div' that meets the condition */
}
.other {
/* Also apply this CSS to .other when 'div' meets this condition */
}
}
So what conditions are supported for responsive styles with EQCSS?
Weight Queries
min-width in px
min-width in %
max-width in px
max-width in %
Height Queries
min-height in px
min-height in %
max-height in px
max-height in %
Count Queries
min-characters
max-characters
min-lines
max-lines
min-children
max-children
Special Selectors
Inside EQCSS element queries you can also use three special selectors that allow you to more specifically apply your styles:
$this (the element(s) matching the query)
$parent (the parent element(s) of the element(s) matching the query)
$root (the root element of the document, <html>)
Element queries allow you to compose your layout out of individually responsive design modules, each with a bit of 'self-awareness' of how they are being displayed on the page.
With EQCSS you can design one widget to look good from 150px wide all the way up to 1000px wide, then you can confidently drop that widget into any sidebar in any page using any template (on any site) and
The question is very vague. As BoltClock says, media queries only know the dimensions of the device. However, you can use media queries in combination with descender selectors to perform adjustments.
.wide_container { width: 50em }
.narrow_container { width: 20em }
.my_element { border: 1px solid }
#media (max-width: 30em) {
.wide_container .my_element {
color: blue;
}
.narrow_container .my_element {
color: red;
}
}
#media (max-width: 50em) {
.wide_container .my_element {
color: orange;
}
.narrow_container .my_element {
color: green;
}
}
The only other solution requires JS.
The only way I can think that you can accomplish what you want purely with css, is to use a fluid container for your widget. If your container's width is a percentage of the screen then you can use media queries to style depending on your container's width, as you will now know for each screen's dimensions what is your container's dimensions. For example, let's say you decide to make your container's 50% of the screen width. Then for a screen width of 1200px you know that your container is 600px
.myContainer {
width: 50%;
}
/* you know know that your container is 600px
* so you style accordingly
*/
#media (max-width: 1200px) {
/* your css for 600px container */
}
You can use the ResizeObserver API. It's still in it's early days so it's not supported by all browsers yet (but there's several polyfills that can help you with that).
This API allows you to attach an event listener when resizing a DOM element.
Demo 1 - Demo 2
I was also thinking of media queries, but then I found this:
http://www.mademyday.de/css-height-equals-width-with-pure-css.html
Maintain the aspect ratio of a div with CSS
Just create a wrapper <div> with a percentage value for padding-bottom, like this:
div {
width: 100%;
padding-bottom: 75%;
background:gold; /** <-- For the demo **/
}
<div></div>
It will result in a <div> with height equal to 75% of the width of its container (a 4:3 aspect ratio).
This technique can also be coupled with media queries and a bit of ad hoc knowledge about page layout for even more finer-grained control.
It's enough for my needs. Which might be enough for your needs too.
For mine I did it by setting the div's max width, hence for small widget won't get affected and the large widget is resized due to the max-width style.
// assuming your widget class is "widget"
.widget {
max-width: 100%;
height: auto;
}
Context: making printable invoices to generate in a browser.
It's common in making printable webpages to use an #media print rule to change the way the content looks for a printed page. Ideally, because I'm printing only a small part of the page, I'd like to hide everything and then display the contents of a particular element.
Structure is something like this:
<body>
<div id="topMenu">...lots of elements...</div>
<div id="sideMenu">...lots more...</div>
<div class="tools">...some tools...</div>
<div class="printing">...some elements I want to print...</div>
<div class="tools">...more stuff I don't want to print...</div>
</body>
Stuff I've tried:
Ideally, I'd like to do something like
body * {
display: none;
}
.printing, .printing * { /* Both parts are needed to make it display */
display: block !important;
}
But this won't work because some elements need to be inline and some need to be block. I've played with some different values for display from MDN and can't find one that easily resets the value to its original. display: initial seems to be treated like inline.
The suggestion in CSS: "display: auto;"? seems to only work for JS.
Of course, it is possible to explicity "hide" the stuff I don't want printed rather than display the stuff I do want, but it seems to me that it should be possible to go the other way.
In this question How to only show certain parts with CSS for Print? suggests body *:not(.printable *) {display:none;} but notes (as backed up on the w3 negation page ) that this is not yet supported.
I note that the w3 draft and the display-outside page seem to recommend using an unknown (to webkit) box-suppress property to preserve the display value while not displaying the element.
My questions:
What is the best way to hide everything and target certain elements for display when they don't all share a common display property?
What exactly does box-suppress do?
Since you specifically tagged this CSS3, try using CSS3!
body>:not(.printing) {
display: none;
}
This should work for the example you gave. I hope it works for your real-world application!
To answer your auxiliary question, as of October 2014, box-suppress is a possible future replacement for display:none that will hopefully make it easier to both hide and remove elements from the flow without worrying about changing its display type (as opposed to visibility still keeps it in the flow, and position:absolute which still keeps it visible). I don't think it's currently supported so I'd stay away from it for now. If you want to know more, see http://w3.org/TR/css-display
You cannot use display for this purpose. See Display HTML child element when parent element is display:none
However, you can use visibility, as long as you use absolute positioning for the hidden content:
body, body * {
visibility: hidden;
position: absolute;
}
.printing, .printing * {
visibility: visible;
position: relative;
}
If you don't use any absolute or fixed elements, you can use an alternative way of hiding elements.
Instead of using display: none to hide your elements, try using:
body * {
position:absolute;
top: -999999px;
left: -999999px;
}
To set it back use:
.printing, .printing * {
position: initial;
/* OR */
position: static;
}
I've got a container which sometimes has three elements, sometimes four. The height of the container is constant.
Are there any bright ideas out there for a CSS-based method for a vertical liquid layout like this?
That is, so the children are either 25% or 33% height, but they figure that out by themselves? (smart kids.) EDIT of course it doesn't necessarily have to be percentage based...
I can do something PHP-based pretty easily, but a more elegant solution would be nice.
Here is a little Sass to make your life easier:
$height: 200px
ul
height: $height
#for $i from 1 through 6
.list-#{$i} li
height: $height/$i
You can also do it with straight CSS:
.list-1 li {
height: 200px;
}
.list-2 li {
height: 100px;
}
...
With PHP, add the .list-# class to the parent element based on how many children there are.
You could also accomplish this in pure CSS with flexbox, but it will not work in the browsers you require.
Well, I've just ended up using a table as the outer container. Table rows added dynamically vertically scale the layout automatically.
Elegant enough, and prevents any PHP processing. Any other solutions welcome, of course (and maybe accepted).
Say you have this definition list (the number of "sets" is not important, just that there are more than one).
<dl>
<dt>Authors
<dd>John
<dd>Luke
<dt>Editor
<dd>Frank
</dl>
I'd like to have these definitions go horizontally. So that you'd get something like this:
Authors Editor
John Frank
Luke
And if you resized the browser so it was too narrow, it would wrap like this:
Authors
John
Luke
Editor
Frank
Is there a way to do this in a good way?
If I've understood correctly the only legal elements in a dl is the dt and dd items, so I can't wrap them in div elements or anything like that. I could split them up in separate dl lists, but that wouldn't really be correct either, as it really should be one list. Any ideas?
There's no valid tag to wrap a pair of dt and dd tags together. A di element was proposed for XHTML 2.0, but XHTML 2.0 never succeeded.
Since there's a pair of inner tags for each item, it's not like a ul, where each li tag can act as an inner wrapper for the content of each list item (in this case acting as a wrapper for each column).
Basically, either use a dl or a ul for each column. Semantic markup is nice, but without a di, a single dl isn't well equipped for this type of layout.
Edit:
As #biziclop mentioned, once CSS3 Multiple-column layout is standardized and supported, it may be possible to break the columns at the correct places (with limited options beyond that layout-wise). Eventually, the code would look something like this:
dl {column-width:100px; column-fill:auto;}
dt {break-before:always;}
Let's play with css3's not-very-well-supported multi-column feature:
Cons:
requires fixed height
won't wrap (unless you write some media queries)
http://jsfiddle.net/rCQbP/5/
dl {
-webkit-column-width: 100px;
-moz-column-width: 100px;
column-width: 100px;
/* fixed height MUST be used */
height: 200px;
}
dt ~ dt {
/* simulate column-break-before: always; */
margin-top: 1000px;
}
I solved this issue using a set of undordered list:
Please view it here: http://jsfiddle.net/radialglo/pXLB4/ Note that the width does not need to be set, but for demonstration purposes I set a large enough width so it would be pushed onto the next line. Drag the html viewport on the fiddle.
<div>
<ul>Authors
<li>John</li>
<li>Luke</li>
</ul>
<ul>
<li>Editor</li>
<li>Frank</li>
</ul>
</div>
and this styling:
div ul{
float: left;
list-style: none;
width: 100px;
margin-bottom: 1em;
}
If you're adamant about using your semantic, I'm not sure of a viable solution. This is because each definition term and its definitions aren't really grouped in a way that is easily stylable?
It's possible with some absolute positioning and nth-of-type selectors (not recognised by old browsers - yuck! - but neither is the media query, so should degrade OK): Demonstration: http://jsfiddle.net/PrJWJ/6/
dt,dd{margin:0;}
#media (min-width:20em) /* 10em per column */
{
/* Enable positioning*/
dl{position:relative;}
dt,dd{position:absolute;}
dt{top:0;} /* All terms at the top */
dd{top:1.3em;} /* 1st dd under a term at 1.3em (factoring in line spacing) */
dd+dd{top:2.6em;} /* 2nd dd under a term */
/* 1st column */
dt:nth-of-type(1),
dt:nth-of-type(1)~dd
{left:0;}
/* 2nd column */
dt:nth-of-type(2),
dt:nth-of-type(2)~dd
{left:10em;}
}
#media (max-width:19.99em)
{
/* Space before a new term */
dd+dt{margin-top:1em;}
}
However, you need to extend this according to your maximum-possible number of rows and columns.
If you can read the Headings ... one's called JWT, the other Alela Diane.. how do I get "Alela Diane" to fill up the space between them ( no puns intended )
The CSS property for these div's is set to display: inline-block.
The HTML - >
<div id="shastra_display">
<div class="shastra_post">
There are multiple div's like this containing the Alela Diane's and JWT's etc.
</div>
</div>
The CSS - >
#shastra_display
{
width: 880px;
}
#shastra_display div
{
display: inline-block;
vertical-align: text-top;
}
.shastra_post
{
width: 270px;
background-color: light-grey;
}
Is it always going to be just two
columns? – thirtydot
It's two columns because the width of
the parent box allows only two to fit.
– Zach
So, the number of columns changes depending on the browser width.
That means you can't "cheat" and do it like this (as suggested by #Stefy):
http://jsbin.com/atimu4
Other than a fixed number of columns, CSS can't do it. See this answer for a comparision of the ideas:
CSS Floating Divs At Variable Heights
You will have to use JavaScript. There's already a convienient jQuery plugin: jQuery Masonry
Some interesting demos:
http://masonry.desandro.com/demos/animating-jquery.html
http://masonry.desandro.com/demos/adding-items.html
You should probably use a 2-column template in order to display the items properly.