How can I move my pseudo element checkbox based on text direction? - css

A common way to make a custom looking checkbox element is to hide the browser's default checkbox and create a pseudo element on the checkbox's label for your custom looking one:
.myclass::before {
<Some styles for the custom looking checkbox>
}
Usually the rendered HTML ends up looking something like this:
::before
<label class="myclass">text</span>
I am having trouble positioning my checkbox based on text direction though. For ltr languages (Like English) Having the checkbox appear ::before the label text makes sense, but it looks awkward in rtl languages (Like Hebrew). Making an identically styled ::after pseudo element fixes my problem, but I don't know how to only apply one CSS style over the other based on text direction. There doesn't seem to be any way in CSS alone to detect an element's computed text direction (unless you're Firefox?)
Any suggestions?

div{
margin: 10px 10px 30px;
}
label{
position: relative;
cursor: pointer;
display: block;
}
span{
content: '';
display: block;
background: #fff;
width: 15px;
height: 15px;
border: 1px solid red;
position: relative;
top: 20px;
}
label strong{
color: #fff;
display: block;
position: relative;
top: -15px;
}
input:checked + strong{
color: red;
}
<div>
<label>
<span></span>
<input type="checkbox"> English
<strong>X</strong>
</label>
</div>
<div>
<label dir="rtl">
<span></span>
<input type="checkbox"> العَرَبِيَّة
<strong>X</strong>
</label>
</div>

I would add a class to the body element, say 'set-rtl'/'set-ltr', assuming you know you're on rtl mode, and then style your elements based on the body class.
In your example it will be:
.set-rtl .myclass::after{
<Some styles for the custom looking checkbox>
}
.set-ltr .myclass::before{
<Some styles for the custom looking checkbox>
}
Another option is to create a different CSS file for each mode.

So I had 2 problems.
My display style needed to be set to inline-block
I had to change my sudo-element's position from absolute, to relative which meant:
removing the initial label's padding (This was space that was set aside for the check box)
Add an equal amount of left and right padding to the check box
vertical-align: middle;
THEN the checkbox flowed ltr or rtl depending on the language just like it's text does.
Basically it boiled down to the fact that I was treating the checkbox as a very separate, specially handled thing.

Related

Why `<a>` tags set as `display:block` have irregular focus outline shape? [duplicate]

This question already has answers here:
Why does display inline-block match height of text?
(2 answers)
Closed 2 years ago.
In Google Chrome only - when I have an <a> tag set to display block, when it receives focus it has an irregular outline shape. (see screenshot).
Irregular outline screenshot
Is this a bug in Chrome or is there some CSS that can cause this issue?
This issue doesn't occur only for <a> elements, it's all focusable elements that behave that way on Chrome. The element area is calculated differently for the actual CSS outline and the focus outline. Not sure the reason why, but the focus handles many functions, for example it can trigger a keyboard, text-to-speech for accessibility, etc. So maybe it needs to be handled differently.
The CSS box for block elements is calculated based on the defined height, width and position. So your element will have the outline defined, and if you have a visible overflow the border and outline don't necessarly match the actual content of the element.
For the focus outline, the text nodes in the element are taken into account in the calculation. The area that is outlined is the combination of the element box plus the text nodes boxes. It's more or less the element box plus the rectangles of the selection range.
In your example, i'm guessing you have a defined height that is less than the height of the text in the element, and so the focus outline has this shape. It takes the area of the text node inside your <a> element + the box of the element.
Best way to handle this would be to set the height to auto, or at least make it so that it encloses the text.
See examples of how the focus outline doesn't match CSS outline for block elements with some overflow:
let a = document.getElementById('a');
a.focus()
div {
display: block;
width: 190px;
height: auto;
font-size: 23px;
border: solid 1px green;
margin-top: 50px;
line-height: 60px;
box-sizing: content-box;
overflow-y: visible;
float: left;
}
#a {
height: auto;
}
#b {
height: 40px;
}
#c {
height: 0px;
}
span {
display: block;
}
<div id=a tabindex="1">
Click
<span>to</span>
focus
</div>
<div id=b tabindex="2">
Click
<span>to</span>
focus
</div>
<div id=c tabindex="3">
Click
<span>to</span>
focus
</div>
The essence of the problem is that the element has display: block with a fixed height and also a font-size which is higher than that block. The text is actually higher than the block model, so it overlaps. Below this is illustrated by giving the background a color.
document.getElementById('nc').focus();
#nc {
display: block;
background: rgb(200,200,200);
font-size: 20px;
height: 15px;
}
<a id='nc' href='#'>Normal content</a>
The chrome browser solves this by 'merging' the outline of both together. Hence the result.
So what to do. That depends on the situation. I can quickly think of 2 solutions, what one to use depends on your context:
#1 Change the height and padding of the block so the text fits
document.getElementById('nc_2').focus();
#nc_2 {
display: block;
background: rgb(200,200,200);
font-size: 20px;
padding: 10px;
height: 1em;
}
<a id='nc_2' href='#'>Normal content</a>
#2 Use display: inline-block instead
document.getElementById('nc_3').focus();
#nc_3 {
display: inline-block;
background: rgb(200,200,200);
font-size: 20px;
}
<a id='nc_3' href='#'>Normal content</a>
Solved this issue by setting <a> with display: inline-block instead of inline, then used margins to adjust.
Occurred when focus set on <a> below:
<a>
<img src="...">
<h1 class="sr-only">Go home!</h1>
</a>
it's not bug , it's built in Chrome and some browsers does the same.
maybe this solve your answer:
a:focus,a:active{
border : 0px!important;
outline : 0px!important;
}
In anchor tag by default outline property is there on focus so we can remove it with outline:none; on focus.so basically its not browser issue. you can try below css to resolve.
a{
display:block;
}
a:focus, a:active{
outline:none !important;
}
Remove outline from anchor

How would I make a form element that selects an option by clicking?

I'd like to have a form element, such as a drop down box, or something of the sort, that displays all of the items at once, similar to a radio button, but without the circle next to it. For example, here is a quick picture I made of what I want
I already know how to make the divs and whatnot, I just need to know how to click it and it automatically turns yellow and is "selected". If it could be JS free, that would help a lot.
You can still use radiobuttons, but wrap them into label and hide input itself. Here's an example at jsFiddle.
HTML:
<label>
<input type="radio" name="item">
<img src="http://lorempixel.com/140/140/abstract">
<div>Some text</div>
</label>
CSS:
label {
display: inline-block;
text-align: center;
position: relative;
overflow: hidden;
}
div {
background: cyan;
line-height: 40px;
}
input[type=radio] {
position: absolute;
top: -100px;
}
input[type=radio]:checked ~ div {
background: lime;
}
Also, you might want to consider targetted browsers :checked support. For example, IE8 and below do not support this selector natively.
You're a little limited without using javascript or anything but you can try the :target pseudo class. Take a look at this jsfiddle: http://jsfiddle.net/rkCSX/

How can I expand this <input> tag?

This is a simplified version of my question earlier today since I didn't get a satisfactory reply.
I have a HTML and CSS code as in this Fiddle: http://jsfiddle.net/wNGHz/
How can I make the <input> resize automatically when its parent frame is resized?
Notes:
I prefer to use only CSS rather than JavaScript.
The <input> should have 100px distance from left and right edges of the parent.
#thirtydot semantically I want to have a simpler HTML. I can wrap
<input> with <div> but it's just weird to add one more element for the
sole purpose of styling another one. I was wondering if anyone has a
better solution.
Unfortunately, there is no better way. It has to do with the fact that input is a replaced element, which means it behaves differently to non-replaced elements such as div.
One difference is that position: absolute; left: 0; right: 0 won't work in the same way on an input as it does on div (except in WebKit).
The best workaround is to wrap the input in a div:
http://jsfiddle.net/thirtydot/wNGHz/6/
<div class="inputContainer">
<input type="text" value="test" />
</div>
.inputContainer {
position: absolute;
left: 50px;
right: 50px;
}
input {
width: 100%;
background-color: red;
color: white;
border: none;
}
When you have input { width: 100%; }, it's usually a good idea to also add box-sizing: border-box, to make any padding and border on the input be counted inside the width: 100%: http://jsfiddle.net/thirtydot/wNGHz/7/
The only pure CSS way I know of is by adding a width in %: http://jsfiddle.net/PeeHaa/wNGHz/1/
You can do this better way.
<div class="inputContainer">
<input type="text" value="test" />
</div>
input {
width: 100%;
margin:0 100px;
}

creating css tooltip formatting issue with underlines in a tag

I'm trying to created a pure css tooltip. I have the test code here: http://jsfiddle.net/RBdn4/
The only problem with this is that in Chrome, the text is underlining on the tooltip despite having the text-decoration: none; line in the css.
Any suggestions on how to get this to stop? The link should underline, but the .tooltip text should not.
Chrome applies the link's text-decoration to the <div> because it is a child of the <a>.
Add a wrapper element around the <a> and make the tooltip <div> a sibling instead of a child of the <a>. Show the tooltip when the wrapper is :hovered.
Oh, and make that CSS make sense!
HTML
<span class="wrap">
this is text
<div class="tooltip"> this is a tooltip</div>
</span>
CSS
.tooltip {
color: #000000;
display: none;
left: 50px;
padding: 10px;
position: absolute;
top: 40px;
width: 250px;
text-decoration: none;
z-index: 100;
}
span.wrap:hover .tooltip {
display: block;
}
Demo: http://jsfiddle.net/mattball/u66GT/
Fix'd. You can't override text-decoration from the child. Also, don't put <div>s in <a>s, as Matt Ball points out.
I wasn't able to prevent the underlining from happening in Chrome while the elements were nested, but I can solve the problem by making them siblings instead.
Simply remove the <div> from inside the <a> tag, and put it next to it instead, like so:
this is text
<div class="tooltip"> this is a tooltip</div>
and use the CSS + selector (adjacent sibling) to select the hovered tooltip, rather than the child selector.
.tooltip{
display: none;
}
a:hover+.tooltip{
color: #000000;
display: block;
left: 50px;
padding: 10px;
position: absolute;
top: 40px;
width: 250px;
text-decoration: none;
z-index: 100;
}
The only change to the CSS from your original is changing the space to a plus sign.
Note the + selector doesn't work in IE6. Hopefully you're not planning to support this crumbly old browser though, right?

CSS to Replace Table Layout for Forms

I've looked at other questions and am unable to find the solution to this. Consider this image: mockup http://img201.imageshack.us/img201/935/image2h.png
I want to wrap divs and stack them vertically. The GREEN div would be a wrapper on a line. The BLUE div would contain an html label and maybe icon for a tooltip. The ORANGE div would contain some sort of entry (input, select, textarea).
Several of these would be stacked vertically to make up a form. I am doing this now, but I have to specify a height for the container div and that really needs to change depending on the content - considering any entry could land there. Images and other stuff could land here, as well.
I have a width set on the BLUE div and the ORANGE is float:left. How can I get rid of the height on divs and let that be determined by content? Is there a better way? Changing all to something else would be difficult and would prefer a way to style all elements or something.
The code I'm using is like:
<div class=EntLine>
<div class=EntLbl>
<label for="Name">Name</label>
</div>
<div class=EntFld>
<input type=text id="Name" />
</div>
</div>
The CSS looks like:
.EntLine {
height: 20px;
position: relative;
margin-top: 2px;
text-align: left;
white-space: nowrap;
}
.EntLbl {
float: left;
width: 120px;
padding: 3px 0px 0px 3px;
min-width: 120px;
max-width: 120px;
vertical-align: text-top;
}
.EntFld {
float: left;
height: 20px;
padding: 0px;
width: 200px;
}
Well, for a start I think you could use less mark-up to achieve your aim. You might have a good reason for wrapping a div around every element of your form, but if it's just to force a single label-input pair to each line then you can nest the input inside the label tag:
<label for="Name">Name
<input type="text" id="Name" />
</label>
This way you can use a simple:
label {display: block; }
to force each pair to their own line. This would also remove the need to float the labels, which removes the need to specify the height of any containing element.
You can still apply multiple classes to the relevant fields/labels, but it's far less trouble. Unless I'm really missing something.
Failing all of that, you could simply add an empty div (or other element), after the last of your fields and style with:
#empty_element {
disply: block;
height: 0;
clear: both; /* to force the parent element to expand to contain this element and, by extension, any non 'position:absolute' siblings that precede it in the mark-up */
visibility: hidden;
}

Resources