Safari not rendering margin-top % values like other browsers - html

I have asked this question before, but thought I'll be clearer. It seems that margin-top in % value does not display the same on Safari, as it does on Chrome, Firefox and IE. In px it displays correctly and margin-left % also.
Here is an example to make comparisons: Fiddle
* {
margin:0;
padding:0;
}
.A {
background-color: blue;
height: 200px;
position:relative;
}
.B {
left: 50px;
margin-top:15%;
width:20px;
height:20px;
background-color: red;
position:absolute;
}
I really need to use a % value on margin-top as it is for a responsive design feature. Using top does not scale the object according to the window size.
Are there known issues, and if so (probably asking a big thing) a way to only target Safari as a browser so I can have custom values for the style sheet?

Yes, according to the W3C standards, margins defined using percentages should be calculated with respect to the width of the containing block.
Ref: (http://www.w3.org/TR/2011/REC-CSS2-20110607/box.html#margin-properties)
However, it appears that Safari calculates top/bottom margin percentages with respect to the height of the containing block, which makes more logical sense, but is nevertheless incorrect as far as W3 standards go.
I don't believe there is a CSS solution for this. You could try some jQuery to target only Safari, get the width of div.A and use it to calculate the margin-top for div.B.
Something like:
var width = $('.A').width();
var topMargin = width * 0.15;
if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
$('.B').css('margin-top', topMargin+'px')
}
else {
};;
Here's an example page: http://www.indieweb.co.nz/testing/safari-margin-percentage.html
Note: This JS only alters the margin when the page is loaded - it won't change dynamically if you manually drag the edges of your browser window; you will need to refresh the page. Wasn't sure if you required that functionality. Let me know if you do and I'll have a look.

Related

How to apply CSS style based on parent element, similar to media queries [duplicate]

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;
}

How to implement simple layout: header - sidebar - content

I'm looking for a simple, effective and modern way to implement the following layout for a website:
- header: 100% width
- below header
- sidebar with fixed width
- content area that fills up till 100%
I've found a good example here, but this is all based on 'em' sizing, we have quite some backgroundpixels so we rather need an example with 'px'.
We thought that we could switch easily to 'px' in that specific example, but apparently it's not that easy to get this perfect.
Thanks in advance for all the tips!
You can use flex to have a sidebar on the left with a fixed width whereas the content on the right takes up the remaining space. Be aware that flex was added with CSS3 and older versions of Internet explorer may not support it (http://caniuse.com/#search=flex)
.contentContainer {
display:flex;
flex-direction: row;
}
.left {
background-color: #ffaa00;
min-width:200px;
}
.right {
background-color: #00aaaa;
flex:1;
}
https://jsfiddle.net/nrv5p70q/1/
However some simple googling could have solved the issue too. You may want to check this cheat sheet:
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
The example you are using will allow you to achieve this.
You can use a em to px conversion to convert the values from em to px. Once you have the correct values you can replace them in the css. Thus.
#nav {
margin-left: -352px; //was -22em
margin-left: expression((-(document.getElementById("wrapper").clientWidth))+"px");
left: 208px; //was 13em;
}
Using this method will allow you to continuing w3schools tutorial which is a great way to get up to speed with html and css.

HTML5, CSS3: Fixed size box with fluid to panel and rest-size bottom panel

I've spent ages scouring Google for an answer to my (relatively) simple problem, but haven't been able to find one.
I want to have a box (div?) in our web based business application that has a height of 100% of its parent container. Within that box, there should be 2 boxes, stacked on top of each other.
The top box should resize according to its contents. (which will never be more than 50% of the total height).
The bottom box should get the rest of the height. Any overflow should scroll.
Preferably no javascript should be used, especially no javascript timers that poll the heights every x milliseconds.
Here's a mockup of the result:
Image of Problem
Is there a solution to this issue?
SEE THE THIRD EDIT, IT IS THE BEST SOLUTION
I believe something similar to this is as close as you can get (assuming they are structured as I believe they are)
/* HTML */
<div id='container'>
<div id='top'></div>
<div id='bottom'></div>
</div>
/* CSS */
#container {
width:300px; /* I assume the width/height is fixed */
height:200px;
border: 1px solid black;
padding:4px; /* To remove the horiz scrollbar with width:100% and a border */
overflow:hidden; /* Hide the content at the bottom to allow scroll */
}
#top {
width:100%;
max-height:50%; /* Using max-height allows it to size to smaller content */
overflow:auto; /* Allow a scrollbar if necessary */
}
#bottom {
height:100%; /* Take up the remaining space */
overflow:auto; /* Allow a scrollbar if necessary */
}
Demo here
On a side note, your question should include the problem, your code related to the problem, and also your attempts at a solution. That way we can understand exactly what your problem is, see that you've tried a solution yourself, and use your actual code to fix it
Edit
In order to get it exactly as you desire, you could use a little javascript
var parent = document.getElementById('container'),
top = parent.children[0],
bottom = parent.children[1];
bottom.style.height = parent.offsetHeight - top.offsetHeight - 8 + "px";
// The 8 comes from the vertical padding of the parent + 4 (not sure what the 4
// is from, probably the four vertical padding widths). The actual number could
// be calculated dynamically, but that would require using getComputedStyle and
// is more work than it's worth since borders/padding don't change dynamically
Demo here
If you don't care about formatting then you could do it in one long line by
document.getElementById('bottom').style.height = document.getElementById('container').offsetHeight - document.getElementById('top').offsetHeight - 8 + "px";
Javascript is needed because you cannot set a height based on another element's variable height in pure CSS like you hope to. For more info on offsetHeight, look here
Second Edit
If you have to make it respond to input (I used contenteditable) you can use the onclick and onkeyup events to bind the function to it. You should have all the tools you need to make it the way you want it now, it is impossible for me to know exactly what you want or how you want it to behave
top.onkeyup = function() {
bottom.style.height = parent.offsetHeight - top.offsetHeight - 8 + "px";
}
top.onkeyup();
top.onclick = function() {
top.onkeyup();
}
Demo here
Third Edit
Not sure why I didn't think about this before, but this is a perfect situation for flexbox. It's simpler, more intuitive, and easier to manipulate. P.S. I included browser prefixes in the demo
#container {
...
overflow:hidden; /* Hide overflow */
/* I excluded vendor prefixes for the sake of brevity, they're in the demo */
flex-flow: column; /* Makes content flow down instead of across */
display: flex;
}
#top {
...
max-height:50%; /* Sets the max height... */
overflow:auto; /* Make sure scrollbar is there */
box-flex: none;
flex: none; /* In essence, this acts like `height:auto` */
}
#bottom {
...
border:1px solid red;
overflow:auto; /* Make sure scrollbar is there */
flex: 2; /* Can be any positive number in this case */
}
Awesome CSS only demo here. For more information on flexbox, check out this article, this video series and post, and also some examples. However, the best way to learn it is to try projects yourself in my view

Wrap background-image to size of browser window

basically I have a little problem with a background I am using. I need it to resize based on what width the window is, because I work with a massive screen and it displays fine, however on 1024x768, it isn't exactly working right. I'll post some images below to show you all what I mean.
On my resolution:
http://imgur.com/Pl87L
On a 1024x768 screen:
http://imgur.com/l6CUe
Also, here is the CSS for my background:
html, body {
width: 100%;
position: absolute;
top: 0;
left: 0;
background: url(/../images/background10.jpg) fixed no-repeat;
}
I hope this helps :).
Ross.
There may be a better way, but I've used jquery before to change (onLoad) the background src based on browser width, something along the lines of ...
function browserSize() {
var bsr_w = $(window).width();
if (bsr_w <= 800) {
$('body').css("background-image", "url(background_small.jpg)");
} else if (bsr_w <= 1024) {
$('body').css("background-image", "url(background_medium.jpg)");
} else {
$('body').css("background-image", "url(background_large.jpg)");
}
}
In you could use the background-size property. Not full support yet but its nice - csspie might also help out on that (think its does as I kind of remember trying this a couple of months back)
There's a pretty useful jQuery plugin that handles this fairly gracefully for you: http://srobbin.com/blog/jquery-plugins/jquery-backstretch/
It might be a bit like using a sledgehammer to crack a hazelnut, but it might do what you need.

Why doesn't IE display this requested background image?

Here's an odd rendering difference between IE and other browsers.
Internet Explorer 8
Firefox 3.5
Chrome 5
See the difference? That vertical line suddenly stops in IE8. That's because IE8 refuses to display a certain background image. Here's a relevant snippet of CSS code:
td#leftbar {
background: url(img/leftbar.gif) repeat-y right top;
width: 100px;
}
You can get additional information by viewing the website on your own computer here: http://labs.pieterdedecker.be/vspwpg/
The problem is not leftbar: It is the leftbartop table cell stretching all the way down to the bottom. That is because leftbartop is in the same table row as the content.
In fact, I think IE is the only browser doing this correctly: All elements in the tr get forced to the same height. IE is ignoring the columns' rowspan properties for some reason. Why, I do not know.
The first thing that comes to mind in terms of a solution - unless somebody comes up with an explanation for this behviour - is having a separate table on the left-hand side with the first (leftbartop) and third rows (leftbarbottom) having a fixed height.
Oh, and using tables for layout is no longer socially acceptable. Just as a side note :)
I'll second Pekka's comment about avoiding tables for layouts, but since proposing serious structural changes would be a bit extreme, the following CSS seem to work well enough to fix the problem:
TABLE#body {
background:url(img/leftbar.gif) repeat-y 94px top;
border-collapse:collapse;
width:100%;
}
TD#leftbar {
width:100px;
}
TD#leftbarbottom {
background:#FFFFFF url(img/leftbarbottom.gif) no-repeat right top;
height:100px;
}
As far as why there is a difference between IE and Firefox/Chrome, the only potentially relevant piece of information that I could find right now was the CSS 2.1 section on table height, which states:
CSS 2.1 does not specify how cells
that span more than one row affect row
height calculations except that the
sum of the row heights involved must
be great enough to encompass the cell
spanning the rows.
So, not only is IE's behaviour bizarre, there's doesn't seem to be a clear cut explanation of what should happen. In IE's case, space required by the multi-row cells appears to be divided up using some sort of relative percentages related to the minimum height of each included row.
To illustrate this, you can cause #leftbar to take up all the space it's leaving empty now by using the following rules:
TD#leftbartop {
height:1px;
}
TD#leftbar {
height:150px;
}
Another interesting example is a 1/3, 2/3 split:
TD#leftbartop {
height:33px;
}
TD#leftbar {
height:66px;
}
Note that if you set the height to something unreasonably small (like 1px in the earlier example), it calculates a height for that cell that is not based on the relative percentage, but something else. I'm not sure where that comes from right now, but I'll play around with the numbers and see if I can take a guess at it later on.