Relatively positioned child covers parent outline - html

I'm running into the following issue. A relatively positioned child inside a parent element that can receive tab focus overflows the parent div slightly, and hides some of the parent's tab focus outline. On Chrome, this outline is partially hidden, and on IE, this outline is completely hidden by the child element.
See this attached JSFiddle: https://jsfiddle.net/55h4wtrc/7/.
.parent {
padding: 0;
border: none;
margin-bottom: 10px;
}
.child {
background: #fff;
border: 1px solid #eee;
position: relative;
height: 40px;
line-height: 40px;
}
<div class='parent' tabindex='0'>
<div class='child'>text</div>
</div>
<div class='parent' tabindex='0'>
<div class='child'>text</div>
</div>
<div class='parent' tabindex='0'>
<div class='child'>text</div>
</div>
Removing the CSS line position: relative; from the .child fixes this buggy behavior.
In my case, i need the outline to be completely visible, and I also need the child element to be relatively positioned. I also need the child element to have a higher z-index than its parent, so no z-index tricks to fix this bug will work.
Any ideas?

Reason
From the CSS Basic User Interface Level 3 specification:
Outlines do not take up space.
and later
The stacking of the rendering of these outlines is explicitly left up to implementations to provide a better user experience per platform. [...]
This means that browsers are pretty free in rendering outlines. If one renders them within the boundaries of an element in question, they might be covered by children.
Mitigation
You can apply custom styling to the outline, using the outline and outline-offset properties to set color, style and position manually during focus, as shown in this JSFiddle, e.g.
.parent:focus {
outline: hotpink dashed 2px;
outline-offset: 2px;
}
If this doesn't work out, you might as well use a completely different tool, such as box-shadow, as shown in this JSFiddle, e.g.
.parent:focus {
outline: none;
box-shadow: 0 0 2px 2px teal;
}

Related

Is it possible to not trigger :hover on ::before or ::after?

I'm trying to make a custom tooltip implementation in CSS, which is working pretty decently, but I'm running into a problem. Currently, hovering over the tooltip still keeps the tooltip opened, even though I'm not hovering over the original element itself.
Of course I've tried something like ::before:hover {display:none;}, but that doesn't work because pseudo-elements don't get pseudo-classes applied to them.
My next thought was to simply make the tooltip not "take up" any space. Using negative margin-bottom allows other stuff to take up space in an element as if the element is not there. However, the :hover pseudo-class apparently still applies then.
Here's a demo of what I'd like to do. I'd like to have the tooltip of the following demo not persist any hovering state. Note that moving the tooltip-text higher above the element is not a working solution, because moving the cursor upwards faster than a snail's pace will cause some pixels to be skipped, which means the tooltip 'catches' the cursor and persists the :hover on the element.
[data-tooltip] {
position: relative;
cursor: default;
}
[data-tooltip]:hover::before {
content: attr(data-tooltip);
position: absolute;
top: -2px;
transform: translateY(-100%);
background: white;
border: 1px solid black;
}
<p>Spacer text</p>
<div data-tooltip="Example tooltip">Hover over me for a tooltip text</div>
As you can see, if you move your cursor over the div, the tooltip will appear, and if you slowly move your cursor up, the tooltip will disappear. If you move your cursor upwards slightly faster, however, it'll skip the 1-pixel gap, and keep the cursor hovering over the div.
Now I'm looking for some styles to apply to [data-tooltip]::before so that the cursor's hover events are not triggered on it (or at least, not at the location you see the tooltip; if I can hide it somewhere at [-1000, -1000] that's fine as well)
So basically, my question is, is it possible to apply css to an element so that :hover does not apply to (part of) an element? I'd love to hear ideas or suggestions.
Not sure if that's what you're looking for, but regarding the first question (red div, blue on hover), you could shorten the divs height and use border-bottom for making up for the lost height:
div {
width: 100px;
height: 50px; /* instead of 100px */
background: red;
margin-bottom: -50px;
position: relative;
z-index: 1;
border-bottom: 50px solid red; /* adds 50px to divs apparent height, but ignored at hover */
}
After looking around the internet for a while I finally found a solution that works flawlessly. I didn't really know about this before, but apparently there's a pointer-events style that does exactly what I want. Its accepted values outside of SVG are auto and none, but luckily the latter prevents all hover-events from triggering on the ::before pseudo-element.
Here's a demo:
[data-tooltip] {
position: relative;
cursor: default;
}
[data-tooltip]:hover::before {
/*** this style prevents persistence of the tooltip when hovering over it ***/
pointer-events: none;
/* the rest is just the styles used in the question */
content: attr(data-tooltip);
position: absolute;
top: 0; /* changed from -2px to 0 so the effect is more clearly shown */
transform: translateY(-100%);
background: white;
border: 1px solid black;
}
<p>Spacer text</p>
<div data-tooltip="Example tooltip">Hover over me for a tooltip text</div>

CSS sector nth-last-child not having specified class or style value

I've been struggling a long tome to figure this one out. Basically, I'll need to find the last child element of some element, which does neither have a specified class property, nor a specified style property.
I have tried everything that has been suggested here, without success.
What I want to achieve, is to make sure the last element inside of a "toolbar" have border-radius, such as can be seen here - https://home.gaiasoul.com/hyper-ide (to right corner)
However, every now and then, one of my buttons are hidden, because they're not supposed to be visible, since they're "disabled" for some reasons. At which point I can't simply use last-child selector, since this might select a button that is not visible.
I cannot use JavaScript, and absolutely not any jQuery.
Example of HTML where it should not select the last-child.
<div class="strip">
<button>1. visible</button>
<button>2. visible</button>
<button class="hide">3. HIDDEN</button>
</div>
Basically, I want a selector that will find the last child element of "strip" from above, but not if it's invisible, which is the case for the last element above.
The reason why my example looks good, is because it does not have an invisible button. I want to accomplish the same, also if there was an invisible button as my last element ...
I have tried nth-last-child with a :not, as suggested in one of the other questions here (which is similar). Here is my current (relevant) CSS, which obviously doesn't work.
.strip {
display: flex;
}
.strip>* {
border: solid 1px var(--border-color);
border-radius: 0;
border-left-style: none;
}
.strip>*:first-child {
border-top-left-radius: var(--border-radius);
border-bottom-left-radius: var(--border-radius);
border-left-style: solid;
}
.strip>*:last-child {
border-top-right-radius: var(--border-radius);
border-bottom-right-radius: var(--border-radius);
}
I have tried
.strip>*:nth-last-child(1 of :not(.hide))
And all sorts of :not permutations, but it doesn't seem to work. Can it even be done ...?
I don't think you will find a CSS solution while the border is applied to the button, as you are trying to apply a rule to a previous sibling element (more here).
However if you are open to applying the border to the wrapper (.strip) you may do something like this...
.strip {
display: inline-flex;
border: 1px solid black;
border-radius: 5px;
overflow: hidden;
}
.strip button {
border: 0;
}
.strip button:not(:first-of-type) {
border-left: 1px solid black;
}
.hide {
display:none;
}
<div class="strip">
<button>1. visible</button>
<button>2. visible</button>
<button class="hide">3. HIDDEN</button>
</div>

Fixed placement of element, but considering pseudo before element

I have an annoying issue with the html layout of a form. I cannot really change the general setup, since it is part of a huge framework. But I have to "move" a button to a more suitable location. I am close, but not happy with the solution so far. Maybe you can give me some idea in this. Here is a dramatically simplified version to demonstrate my approach:
I have two container divs, top and bottom.
The top container shows a button on the left side. That button is fixed, but can have a different width due to the translation of its label.
The bottom container holds lots of stuff. Amongst that a second button at its top which works fine, but looks wrong. I want to optically move it into the top container, since there is a logical connection to the button in there. Sure, really placing it in there would be the correct solution, but I currently cannot do that. Instead I use a fixed position which works fine, except for the horizontal placement. I have to decide how far pushed from the left to place the button, so that it certainly does not overlap the first button in the container. I obviously have to consider all translations, the result works, but depending on the first buttons label I have an annoying horizontal gap between the two buttons.
I tried to use a pseudo element (::before) on the second button to help with the layout. Since when rendering the view I obviously have the translated label of the first button I can copy that into some property of the second button and use that property in my css to fill a before pseudo element of the second button which has exactly the same length as the first button. That is what is shown in the code example posted below.
What I completely fail to do is to place that pseudo element such that is it left in the top container (so exactly below the first button). The idea is to indirectly place the second button that way. Looks like this is not possible, obviously. But since I am a bloody beginner in markup and styling I thought it might be worth asking here...
Below is some drastically stripped down code to demonstrate my approach.
I create a jsfiddle for you to play around with. Here is the code:
HTML:
<div id="top-container">
<button>multilingual button text</button>
</div>
<div id="bottom-container">
<h2>
Some title opening the bottom container
<span class="into-top-container">
<button id="place-me" reference-text="multilingual button text">button to be placed</button>
</span>
</h2>
<p>Some content</p>
<p>Some content</p>
<p>Some content</p>
</div>
CSS:
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
div {
margin: 0;
padding: 5px;
}
button {
margin: 0;
padding: 5px;
white-space: nowrap;
}
div#top-container {
width: 100%;
border: 1px solid green;
}
div#bottom-container {
width: 100%;
border: 1px solid blue;
}
#place-me {
position: fixed;
top: 0;
left: 400px;
margin: 5px;
background: yellow;
}
#place-me::before {
z-index: 0;
/*visibility: hidden;*/
position: absolute;
content: attr(reference-text);
margin: 0 5px;
padding: 0;
background: gold;
right: 100%;
}
Notes:
that in the above code the second button is placed with left: 400px;. That is more or less what I want to change. But obviously left: 0 is not correct...
the visibility css rule for the pseudo element is currently commented out for demonstration purpose
keep in mind that the second button is *not* contained inside the top container, but actually logically below the title of the bottom container. The goal is to move it optically up into the top container which already is where close to what I want. Except for the horizontal alignment...
Upon request here is a screenshot:
It is taken from the fiddle I posted above. I added the red ellipse which shows what element pair I want to move and the left pointing arrow indicating where I want to move that too. I want to move it exactly that far, that the two tests "multilingual button text" are exactly placed on top of each other, but without specifying an explicit left placement obviously. That is why the pseudo element exists: as a dummy placeholder. I would then hide that pseudo element and have the second button placed exactly right of the first button, regardless of how long the translated text in there is.
So the final result should like like that:
OK, I invested some more time, since this issue popped up again after a regression in our code and I found, as often after allowing some time to pass, a logical and relatively clean solution:
I use the same stripped down code to for demonstration purposes.
The jsfiddle is based on the one provided in the question itself.
HTML: no real change, except for the reference-text having moved from button to container, for the why see below:
CSS:
* {
font-size: 12px;
font-weight: normal;
font-family: Arial;
}
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
font-size: 12px;
font-weight: normal;
}
span,
div {
margin: 0;
padding: 5px;
}
button {
margin: 0;
padding: 5px;
white-space: nowrap;
}
div#top-container {
width: 100%;
border: 1px solid green;
}
div#bottom-container {
width: 100%;
border: 1px solid blue;
}
span.into-top-container {
position: fixed;
top: 0;
left: 0;
pointer-events: none;
border: 1px solid transparent;
}
span.into-top-container::before {
visibility: hidden;
content: attr(reference-text);
position: relative;
margin-right: 5px;
padding: 5px;
border: 2px solid;
background: gold;
}
#place-me {
background: yellow;
pointer-events: all;
}
The basic change in strategy: it is the container holding the button to be placed that has to be positioned in a fixed manner, not that button itself (so the <span class="into-top-container">)! That allows to use the pseudo before element, now also anchored to that container, not the button, to take the space as required without actually getting part of the button itself.
Since that container is now place over the original multilingual button that one is not clickable any more. That issue is fixed by a css pointer-events set to none for the container and set to all for the placed button again. That makes the container itself simply ignore all events (clicks) and have them passed to the original button beneath.
I had to make sure that the font used inside the pseudo element is style exactly like the original multilingual button. That actually makes sense, since the font styling defines the actual width used by that button, so the actual width used by the pseudo element should be defined in exactly the same manner. In the example above I forced that by simply setting all elements font style rules to some fixed values (the initial * {...} in the CSS code). That can obviously also be done right inside the css rules for the pseudo element itself. I chose the more simple and brute variant here to keep the code clean.

CSS Float adding to the height of button

OK something strange is going on here, i am using a class for 2 buttons that share styles. But when i apply a float right to one of the buttons it makes it bigger 26px vs 30px in my real world example.
It is only changing by 1px in this http://jsfiddle.net/Mag2D/ but it is still different.
I have a screen grab of inspect elements that show the 26 vs 30 here http://imgur.com/3WJdvcQ
This is the CSS that is being used...
.orderButton {
position: relative;
-moz-borderradius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
background-color: #004282;
color: #fff;
padding: 5px 35px;
}
.right{float:right;}
Any idea why this is happening?
The answer is that when you float an inline element, it then becomes an inline-block element, which changes the way padding/width/height/margin properties are painted.
Whenever you have an inline element (e.g. span, a, etc) that you want to add padding to, make sure you set it to display: inline-block. It will display much more consistently cross-browser and, most likely, will be more likely to display the way you intended it to.
You have 2 issues here: 1) anchors are not block level elements. 2) when you float non-block level elements, they get turned into an inline-block level element and thus their model is changed.
If you set both to be floated by adding a "left" class to the left button and adding the float, they come out perfect.
HTML :
<a class="orderButton left">Place Order</a>
<a class="orderButton right">Place Order</a>
CSS :
.orderButton {
position: relative;
-moz-borderradius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
background-color: #004282;
color: #fff;
padding: 5px 35px;
}
.right{float:right;}
.left{float:left;}
Solution #1:
Add this in the CSS:
.left{float:left;}
And add left class to the a tag
<a class="orderButton left">Place Order</a>
Solution #2:
In .orderButton, add:
display:inline-block;
When you float an element, it automatically becomes a block box. This box can then be shifted to the left or right on the current line but it also changes its margin, padding etc.
Demo #1 - With float on both a tags
Demo #2 - With inline-block; on the button class instead

Decorating DIV and using full page width via CSS / CSS :before and :after

I'm writing a page that looks code wise like
<div class="green">
<span class="orange">s1</span>
<span class="orange">s2</span>
</div>
but that should be formated via CSS like:
The surrounding black frame shows the full page in the browser. (Think of <body></body>)
The red frame is a fixed width and fixed hight basically empty space that should be added by the CSS .green:before (I'm using it's ability to format it's borders for a visual effect)
The green frame shows the real content that should be as wide as necessary to contain both <span> in one line
The blue frame should be created by the CSS .green:after, has a fixed height and should take up all the space till the right border of the page - i.e. it must have a variable width.
Required browsers are the modern ones (Firefox, Chrome, Safari, Opera) in recent versions. No need to take care of IE. Mobile browsers would be great, though.
How can I achieve that? (All my attempts failed sooner or later...)
A jsFiddle with this example code is at http://jsfiddle.net/X2MDG/
I'm afraid that there is no way to satisfy all your constraints. The main things that don't seem to have a CSS solution are:
Controlling the width of just the green bit can't be done without affecting the width of the red :before and blue :after content. As you mention in the comments to the question, using a different DOM structure is not an option.
The blue (:after) content should take up all space not needed by the green (main) content.
The fixed height of red/blue may require some clearing on the elements below the entire div.
So, as far as I could tell, the question as you asked it doesn't have a 100% satisfying answer. Either way, here's the code I came up with researching this problem, perhaps it can help you or others stumbling on this question. See either this jsfiddle or the code below:
<div id="page">
<div class="green">
<span>Orange 1.</span>
<span>Orange 2. Which can be really wide.</span>
</div>
<p style="clear: both;">Black is the page. Clearing is
needed because the red and blue boxes are not in the
flow but do have quite some height.</p>
</div>
CSS:
div#page {
border: 2px solid black;
width: 80%;
padding: 2px;
}
div.green:before {
content: 'red / before';
border: 2px solid red;
float: left;
display: inline-block;
width: 140px;
height: 200px;
}
div.green {
border: 2px solid green;
}
div.green:after {
content: 'blue / after';
border: 2px solid blue;
display: inline-block;
float: right;
height: 60px;
}
div.green span {
border: 2px solid orange;
}