Imagine I have this setup:
<div class="dialog">
<div class="toolbar first">Bla</div>
<div class="toolbar">Yada</div>
</div>
and this style definition:
.toolbar { background-color: red; }
I actually want a small 2 pixel border between the 2 "toolbars", so I see 2 general possibilities,
1) add a background colour to the "dialog" div and a margin to the first "toolbar":
.dialog { background-color: #fff }
.toolbar.first { margin-bottom: 2px; }
2) add a 2px border to the first toolbar:
.toolbar.first { border-bottom: 2px solid #fff }
Is there any difference in terms of "cost" of rendering/applying? Which is more desirable to that extent?
I know this is a very small example and it might make no real difference, but imagine a page with tens of these dialogs (dialogues?).
What a timely question!
I read this excellent article a couple of days ago about performance for CSS. Granted that CSS selector performance is tiny compared to the effort expended on serving an entire page, but it's still something to keep in mind.
http://css-tricks.com/efficiently-rendering-css/
EDIT
I didn't notice that the question was about CSS rules and not selectors. Trying to answer that question now.
Like I said in my original answer, CSS performance is the area you'll be able to gain the least amount of performance in your system (generally, unless you're using things like filters), and should be addressed last if you want to micro tune your site. It's better to keep it readable and work on the other parts of your site first.
I think we'll see real difference in performance only with tens of thousands of elements otherwise it'll stay in the millisecond margin.
So my advice it to stick with the most readable/simple way which is probably adding the "direct" border to the first toolbar. :)
personally I think your second option is the best, you're adding a border so use border ;) - however I'd do it reverse and add the border to the second toolbar.. imagine you have more than 2, what you actually want is for the second and subsequent ones to have a top border, but not the first
.toolbar { border-top: 2px solid #fff }
.toolbar.first { border: 0;}
that way that .first class is doing it's job and specifically overriding
Without knowing the which browser, and how the css is implemented, how the elements are rendered, which can vary by platform hardware, It's very difficult to find out. What may be slow today might be fast next month( and vice versa!)
About the only assumption you can make is that all browser vendors want their code to perform as fast as possible...
Keeping your CSS readable, consistent, and maintainable is much more important than 'performance'.
I would recommend to write it the way it is meant, and optimize only if you have reason to do it. If the space belongs logically to the dialog, then you should add it to the dialog, and then you can probably discard the "first" declaration.
Even if you have hundreds of this dialogs you won't notice a difference, anyway it's the client browser who will render the page and the server is not affected.
So to answer your question, yes some operations are more expensive than others, absolutely.
They generally fall into 2 categories:
Reflow triggering css styles
Non-reflow triggering css styles
Examples of styles that trigger reflow in general:
Width
Height
Margin
Padding *only if it affects adjacent elements
Float *only if it affects adjacent elements
Flex properties
Borders that affect
Basically anything that causes a portion of the DOM other than the current element to have recalculate its size
Removing elements at the top or middle of a list
Examples of styles that don't trigger reflow:
Background image
Background-color
Color
Border color
Padding * as long it's only on the current element and doesn't affect sizing for adjacent elements
Removing an element at the bottom of a list or on a section that doesn't cause other elements to have to recalculate their positions/sizing/etc
Related
I am trying to get the blue rectangle container to have a larger z-index than the other boxes when hovering over elements that overflow the container.
Game 3 here has the larger z-index, but I want to access the Loser select in the blue circle below, however I can't, unless I hover back over the blue rectangle to gain focus.
Is there a way around this where it can be handled with just CSS or do I need JQuery?
I created a Fiddle that can replicate this so ignore any JS errors as the actual page requires quite a bit of includes, however the issue is in tact. Hover over the 4th game which has three dropdowns, Source, Pools, Seeds. You can select Seeds just fine. However, hover over another game at the top then come back down to "Seeds", you can't select it unless you hover over "Pools" again. I need "Seeds" to always be selectable regardless of what the overflow is.
https://jsfiddle.net/cblaze22/qp4L15tj/8/
Current Code For Game Hover (Blue Rectangle area)
The .forward puts a large zindex on the blue rectangle area.
$(element).hover(
function () {
if (!$(this).parent().hasClass('editing')) {
$(this).addClass('forward');
}
},
function() {
$(this).removeClass('forward');
}
);
This was actually a surprisingly easy fix once you understood the structure and the actual problem. Div's covering div's. First you disable all click events on everything within .bracket-part as they aren't needed. Then you add the click events back onto the selects. To make it more generic for easier use again you can simple change select in the CSS selector a class .re-enable-events or something. The JS about z-index's wasnt actually needed.
#bracket-wrapper .bracket-part select {
pointer-events: all !important;
}
#bracket-wrapper .bracket-part {
pointer-events: none;
}
See: https://jsfiddle.net/uws8pf1y/
Pointer events has a very good compatibility rate so this solution should be fine across pretty much all devices.
To get straight to the point: There is no clean CSS-only solution to your problem.
Since all your elements are pretty much identical (and by that I mean the class for example) you will not find a solution that covers all configurations. Since they do not differ from each other they all have the same z-index but not the same stacking context. Unless you give their parents a different z-index or change the stacking context you will not be able to access the blocked element. It also comes down to how limited you are with changing the code. The code looks like it has been build by JS and you just copied it to your fiddle for us to test.
Attempt #1
Attempt #1 is to just add high z-index directly to the according parent.
#mmshr already tried to do this. However, he tried to give the whole class a high z-index which is not gonna work out of course as you've already pointed out.
You could however try to only give this element a high z-index element in its style attribute. This comes down to how limited you are with changing the code. You could theoretically use JQuery for this but the way you would select the element (e.g. by nth-child()) brings me to Attempt #2 which uses the same pseudo-class and is a CSS-only attempt so using JS is nonsense in this case. By the way if you can change your code like this you could remove your little JQuery function that adds the forward class on hover.
Attempt #2
This attempt works fine and you are not limited by the ability to change code since this is pretty much one line of CSS. As already stated in Attempt #1 you could use a pseudo-class to select this element. However, this is not valid for all configurations. If you would add one element (<div data-bind="template: { name: 'bracket-template', data: $data }">...</div>) before your blocked element you would have to change your CSS each time. But if there is no need for changing elements and configurations (or at least not the order) this is a valid solution:
#bracket-wrapper > div > div:nth-child(8) > div > div {
z-index: 2 !important;
}
In this attempt you can (and have to) remove your little JQuery function too:
$('.bracket-part').hover(
function() {
debugger;
$(this).addClass('forward');
},
function() {
$(this).removeClass('forward');
}
);
Remove the entire thing.
Attempt #3
Probably the cleanest and best attempt is to use the stacking context. The stacking context is explained right here. But to give you a simple overview (W3C):
Each box belongs to one stacking context. Each positioned box in a given stacking context has an integer stack level, which is its position on the z-axis relative other stack levels within the same stacking context. Boxes with greater stack levels are always formatted in front of boxes with lower stack levels. Boxes may have negative stack levels. Boxes with the same stack level in a stacking context are stacked back-to-front according to document tree order.
Most important is this part because it applies to your structure:
Boxes with the same stack level in a stacking context are stacked back-to-front according to document tree order.
If you take a look at your HTML tree you will find the following:
According to the stacking-context we should be able to give your element in the background a higher stacking-order then your element in the front by changing the order of those elements in your tree.
It is just a guess but you probably have something like an array where you store the data and some JS-file builds a tournament bracket out of it. If you could somehow change the order of those two elements (for example by changing the order of your array) you would not use CSS and would not use any additional JQuery.
What if none of these work?
Well, then I do not see any solution that requires only CSS.
I also thought about a possible JS solution but this is a tough one and I couldn't figure out a (simple) solution. Let me explain the problem:
Since your select is behind a div element JQuery would not recognize it (e.g.) on hover so you would have to use pseudo-classes again which I already covered with a CSS-only attempt.
I also thought about adding a z-index of -1 to the blocking element, because JQuery could recognize it on hover. But this leads to problems too: the blocking element is now in the background and the blocked element in the front and you can also click it. The problem is that the (former) blocking element is now behind the #bracket-wrapper. This is also not a valid solution because you would have to use a pseudo-class again to target this specific element.
Conclusion
I am gonna be honest with you: This tournament tree is poorly designed and structured. There shouldn't be overlapping elements or elements outside of a container and certainly not both in combination. If none of my attempts are suitable I do not see any CSS or JS solution. At least not a simple one. You have provided little information about how the tournament tree is build but things could change if you do.
At this state I think rebuilding this whole structure is the only really clean solution.
Edit
Solution #1 by #Deckerz
#Deckerz provided a great solution which does not focus on the z-index. Instead, it uses pointer-events. I tried this approach but failed because I forgot an important part. The logic behind it is simple:
First you disable all click events on everything within .bracket-part as they arent needed. Then you add the click events back onto the selects. To make it more generic for easier use again you can simple change select in the CSS selector a class .re-enable-events or something. The JS about z-index's wasnt actually needed.
#bracket-wrapper .bracket-part select {
pointer-events: all !important;
}
#bracket-wrapper .bracket-part {
pointer-events: none;
}
However, this is still a workaround. I still recommend restructuring your code and CSS.
If you want Seeds to always be selectable, why not always give it's bracket-part parent a high z-index?
Right now, the z-index is only high after the bracket-part is hovered. Although Seeds is technically a child of the bracket-part, it is positioned outside of it, so unless the Seeds select is hovered directly after bracket-part is hovered then it won't be selectable.
If you add z-index: 10000; to Seeds' bracket-part parent styles, Seeds will always be selectable:
<div class="part bracket-part ui-draggable ui-resizable ui-draggable-disabled ui-state-disabled" data-bind="bracketPartInit: { left: $data.left, top: $data.top, height: $data.height, width: $data.width, disabled: $root.members.bracket.disableDrag, minHeight: $data.minHeight }, css: { 'dash-top' : $data.dashedBorderTop(), 'dash-right' : $data.dashedBorderRight(), 'dash-bottom' : $data.dashedBorderBottom(), 'dash-left' : $data.dashedBorderLeft(), 'reverse-bracket' : $data.type() == 2, 'box-bracket': $data.type() == 13, 'bye': $data.bye()}" aria-disabled="true" style="top: 459px; left: 0px; height: 80px; width: 150px; z-index: 10000;">
Having seen advice seemingly change over the years regarding use of empty DIVs (ie. <DIV CLASS="somediv"></DIV>) I'm confused as to the current thinking over whether or not to use when a DIV will have no inner HTML.
I can find no definitive confirmation over whether we can rely on all modern browsers to display background color and image correctly at the specified width & height when there is no inner HTML, so I'm thinking maybe we can't rely on it - yet it's such a seemingly basic area.
I have even seen suggestions that empty DIVs should never be used - but do specs really state it is 'wrong' to have empty DIVs, or is it just unreliable? (I've tried finding reference to them, but maybe I'm using the wrong terms).
To illustrate, here are 5 areas where I would normally use an empty DIV, in the absence of any recommended alternative:
as a placeholder for content which will subsequently be fetched by XHR calls
as a way to manually create space in a layout
where an image is defined in CSS (as a background image, but will effectively be foreground)
where the text will come from the CSS using .somediv:after{content:SOMETEXT}
where CSS is used to display graph bars etc using solid background color
Maybe there are different answers for each of these, which might explain the complexity over this issue.
I have, of course, tried discovering already, but for example the SO question Is necessary to show an empty <div>? suggests to me there is a huge amount of "IMHO", "probably", "seems to work" in this area. I would expect that by now that some official consensus has been reached on best practice.
So.. should I use and if so should I set font-size to the same as the smaller of DIV width/height to ensure that space is filled in all browsers? Are there any other CSS tricks to ensure this will work in all browsers?
The browser is not going to discard or forget your container just because it does not have any contents (yet).
If you want the container to have a specific placeholder shape, then you might give it min-height, min-width, height and width and make sure it's display: block;.
If you are still unsure, you can fill it with a spacer.gif/png without padding and margin.
http://jsfiddle.net/APxNF/1/
Short answer. Yes, browsers will render the div even if there is no content.
Long answer, That might now always be the case. I have worked in the web for 8 years now and never had to use these, but here they are anyway.
jsFiddle demo
HTML
<div class="empty1"></div>
<div class="empty2"></div>
<div class="empty3"></div>
CSS
.empty1 {
background: #FBB829;
height: 100px;
width: 100px;
}
.empty2:before {
content: "\00a0";
}
.empty2 {
background: #FF0066;
height: 100px;
width: 100px;
}
.empty3 {
background: #F02311;
min-height: 1px;
height: 100px;
width: 100px;
}
Sources:
Experience
Empty div with 2px width and background color doesnt show with height as 100%
http://csscreator.com/node/36023
Lately I'm using a CSS structure that makes HTML much cleaner but I don't know if there's something wrong with this.
Instead of using:
.top { //properties }
.top-wrapper { //properties }
.top-logo { //properties }
And for HTML:
<div class="top">
<div class="top-wrapper">
Logo
</div>
</div>
I'm actually coding like this:
.top { //properties }
.top .wrapper { //properties }
.top .wrapper .logo { //properties }
And for HTML:
<div class="top">
<div class="wrapper">
Logo
</div>
</div>
Is it wrong to do this?
It is not wrong, but the more selectors you have, the higher the resulting specifity of your style. For more information about specifity see http://www.w3.org/TR/CSS21/cascade.html#specificity.
Imagine your example
.top .wrapper .logo { font-size: 10px; }
followed by this:
.logo { font-size: 20px; }
The <a class="logo"> will have a font-size of 10px, even though you specified it to be 20px for the second declaration.
It isn't necessarily "wrong" to do this, it works and if you find it easy to use I'd say go for it!
However - there are some drawbacks to this approach, for example your CSS file will end up larger, which will mean longer download times for anybody viewing the website (granted this effect may be negligible)
There's also the issue that, if you want to re-use the styles of top-wrapper on another element, you have to place that element inside a div with a top class, this ends up cluttering your HTML.
(For more information on the above point see OOCSS)
At the end of the day there are benefits and drawbacks to any approach, if you feel really comfortable with this approach, and it is working for you - then stick with it!
EDIT:
It should also be noted that you're second approach will take longer for the browser to render than you're first approach (the browser has to check multiple conditions instead of just one) for more info see this question
Nope.
What your second code is doing is saying, "target all the elements inside elements that have class top, that have the class wrapper and apply such and such properties"
On the other hand, your first code is only targeting the elements that have the class top-wrapper (or whatever) regardless of their parents class.
Depends how you will use that specified class
.logo { //general properties }
.top .wrapper .logo { //specific propery to top wrapper properties that overrides .logo }
.bottom .wrapper .logo { //specific property to bottom wrapper that overrides .logo }
HTML
<div class="top">
<div class="wrapper>
Logo
</div>
</div>
<div class="bottom">
<div class="wrapper>
Logo
</div>
</div>
Generally, it is better
It's not wrong, but it may get verbose and a little slower if you are have 10 levels of nesting. The result may also be harder to debug if both .logo and .wrapper .logo are styled.
On the other hand it may be nice to have a .button looking different in .content or in .menu. In general, use what makes sense in a specific use case.
No right and wrong here: everything depends on the site you are building, if you are in a team and what makes sense to you.
Personally I don't think the html is any cleaner now than it was previously (in this small example) but your CSS specificity has increased and that could have a detrimental knock on effect.
I now ask myself 'why do I want this element styled in this way?'. Sometimes it's because of inheritance, sometimes because it's a specific case that happens to be in a certain area. The example you use seem a good candidate for inheritance, but looking at the rest of the site might lead to a different conclusion.
Adding longer class names doesn't, to my knowledge, greatly decrease performance. I suspect the only effect would be marginal and is unlikely to be noticeable. Really dependant on the implementation
Additionally if you were 'reading' the html it may make more sense to read have class names like top-logo, other wise you need to look for the appropriate ancestor (bearing in mind there may be more than one that could be applicable).
I'm busy moving toward an OOCSS / BEM method (google these for more, so many resources out there...) myself because I believe it will make maintenance easier in the future, plus I find it makes more sense within a team environment. These are approaches that could lead to 'classitis' or otherwise 'messy' html. I don't mind that though and think the larger the site the more sense this makes. If you're making a 4 page site, maybe don't bother.
But this works for me and may not for you. So I go back to my original statement, there's no right or wrong here :)
I have a two column layout, with a gray sidebar on the right. I need the sidebar's height to expand when the height of the left column is increased (due to content being dynamically expanded). I can make the sidebar fit a static page, but I cannot get it to increase in size with the rest of the page. Did some Googling, but couldn't find a work-around that worked for me.
Does anyone know how to do this?
This is a common problem when using DIVS for this type of layout.
If you google 'Faux column' you should get some answers.
eg. http://www.alistapart.com/articles/fauxcolumns/
This may be slightly off but if you use jQuery on your site you can perform a quick calculation and resize all DIVs sharing a similar class to the maximum height:
$('.elements').height(Math.max($('#div1').height(), $('#div2').height()));
I have been haunted by this problem for a while and I wrote an article about this issue: Done with faux columns. Here is what I argued:
JavaScript based solution for this
problem is not worse than any other
solution. In fact if you are using
JavaScript, you may save a few hours
of frustration of trying to get things
working. People will warn you against
this by saying “What will happen if
the user turned off JavaScript?“.
Believe me, if the user has turned off
JavaScript, most of the web is broken
for him anyway. Your sidebar does not
matter to him.
As cballou mentioned, the simplest way to do this thing is to use JQuery code:
$(".sidebar").height(Math.max($(".content").height(),$(".sidebar").height()));
I changed the background-color to the same color as my sidebar, on that specific page, although I do have backgrounds for all my sections rather than one overall background. But that might not work for everyone.
In my stylesheet,
.sidec
{
background-color:#123456;
}
In my HTML page,
<body class="sidec">
content....
</body>
I recently saw a quite creative solution to this problem using the CSS properties position:absolute and border.
Definitely worth checking out to see if it works for you.
Link: http://woorkup.com/2009/10/11/really-simple-css-trick-for-equal-height-columns/
I'm not sure if this will help, as I'm a newbie. However, when struggling with getting my sidebar to show the whole content when I doubled it's size I did the following. I was changing my height and width with no response until I changed the class. My class was listed SB frame SB width. So when I changed my class to read SB height SB width it fit to my content instead of the original frame size. I also tried SB max sb width with worked too, but it took out my footer menu bar (meaning it wouldn't show it anymore). I went back to SB height SB width, and all is well. That's super duper elementary for all of you I'm sure, but just in case there is another newbie reading this that doesn't understand much about html code like myself... I hope this helps =)
Happy Holidays Everyone!
hugs, tara
I'm guessing you want to apply certain effect to your layout such that it will require both columns to resize together. If you want to dynamically change the values of the height of the columns, I doubt it will work simply with css unless you implement some javascript to control the style.
As Dal suggested, do look at the link on faux columns. As the name suggests, the solution isn't much about modifying the columns height. Instead, it gives the "illusion" that both columns appear to be of the same height when in reality they are not -- and is with the use of tiles of background image.
The idea is there isn't a need to complicate the mark-up. Simple structure with a touch of "illusion" with images is a common practice in web design.
Regards,
Jonah
With the poor attitude towards new members on here I expect to be barracked for this answer, here goes.
I got around this problem by creating a background image 960px wide 1px high with the two colors I needed for the columns in their respective widths (780px and 180px). I then used this as the background image for my container repeated on the y axis and made the content and the right sidebar background-color: transparent.
.container {
width: 960px;
background-color: #FFFFFF;
margin: 0 auto;
background-image: url(../images/bgs/conbg.jpg);
background-repeat: repeat-y;
}
.sidebar1 {
float: right;
width: 180px;
height:auto;
background-color:transparent;
padding-bottom: 10px;
}
.content {
padding: 10px 0;
width: 780px;
background-color:transparent;
float: right;
}
I am sure that this method has its limitations but it works perfectly on all my pages.
It is possible that I have not explained this very well, if so, be nice about it will you please. I will endevour to expand on my method(which is probably already common knowledge).
It often works out great that the CSS backgrounds don't print, however, sometimes I use them to convey contextual information. What is the best way for getting around CSS backgrounds that don't print but you really want to display. The example, I'm currently working on is a table that displays financial information. Different background colors are used to indicate how "good" a number is (e.g. very profitable, profitable, neutral, negative, very negative).
I've used borders to simulate backgrounds when I really need a background color. Something like this will work (but I apologize for not having tested this):
div.must-have-background-for-print {
position: relative;
width: 400px;
}
div.must-have-background-for-print div.background {
position: absolute;
top: 0;
left: 0;
height: 100%;
border-left: 400px solid #999;
}
In response to #Steve Quezadas' comment, the idea is that rather than using a background, you insert an element into the element that needs the background and apply an extremely wide border to it so that it fills the outer element. This will most likely require that the contents of that element also are inside of another wrapper so that they appear above the new background element...
If you started with this:
<div class="has-background">Some stuff in here</div>
You might use this:
<div class="has-background">
<div class="background" />
<div class="content">Some stuff in here</div>
</div>
This is extremely ugly, but I've used it in the past and it does solve the issue of background colors not printing. And, before you ask, you'll have to adapt the css to your specific case. I'm simply describing the concept of using borders to replace backgrounds. Your implementation will depend on how your page is structured and this is extremely difficult to do if you don't have either fixed widths or heights on your elements.
Two suggestions:
Color-code text in the table rows
Add color-coded icons to the beginning or end of the table rows
You could even incorporate these into the normal view with your background colors.
I ran into the same problem color coding tabular data in html, eventually I just switched to pdf generation for color printouts and only made black and white available in html
It's a browser setting. Turn on background printing in IE. So, you can either change the browser settings (possible if on an intranet) OR just export your report to Excel or some other format for printing.
You could make the font bigger and/or bold and/or italic and/or colorful.