2

I'm writing my own CSS reset and I encountered a problem. Let's say I have the following HTML and I reset it using the given styles.

* {
  margin: 0;
  padding: 0;
  border: 0;
  font: inherit;
  font-size: 100%;
  line-height: 1.2;
  vertical-align: baseline;
}
body {
  margin: 10px;
  font-family: sans-serif;
}
<p>
  <input type="checkbox" /> <span style="font-size: 2em;">Red</span>
</p>

This doesn't really work because of the different rendering of input elements, in this case, the checkbox. See the following examples.

Chrome
enter image description here

Firefox & IE
enter image description here

Both checkboxes are 13x13 pixels, but Chrome's actual (visual) size is 12x12 pixels. It has a drop-shadow effect, which makes it 13x13 pixels. If I want it to align properly, I need to use vertical-align: -1px on the checkbox.

enter image description here

but if I do that, it'll apply the style on other browsers too. So I need to apply vertical-align: -1px only on Chrome. Is there a way to accomplish this? Maybe something like

input[type="checkbox"]:(if-chrome) {
    vertical-align: -1px;
}

Update: I've managed to customize the checkbox on Chrome which is nice, but IE doesn't support appearance, and even though Firefox applies -moz-appearance: none, it changes checkbox border-style to inset and doesn't let you modify it. And later finding out that appearance is non-standart (dropped css3 features) was a huge disappointment. I'll have to wait for CSS UI 4, I guess.

* {
  margin: 0;
  padding: 0;
  border: 0;
  font: inherit;
  font-size: 100%;
  line-height: 1.2;
  vertical-align: baseline;
}
*,
*:before,
*:after {
  box-sizing: inherit;
}
body {
  margin: 10px;
  font-family: sans-serif;
  box-sizing: border-box;
}
input[type="checkbox"] {
  -webkit-appearance: none;
  width: 13px;
  height: 13px;
  border: 1px solid DarkGray;
  position: relative;
}
input[type="checkbox"]:checked:after {
  content: "✔";
  font-size: 11px;
  font-weight: bold;
  line-height: 1;
  position: absolute;
  left: 1px;
}
<p>
  <input type="checkbox" /> <span style="font-size: 2em;">Red</span>
</p>
akinuri
  • 10,690
  • 10
  • 65
  • 102
  • 6
    This is definitely bad practice - for a long time browser hacks were used to resolve problems in Internet Explorer, but generally these days it's preferable to find a solution that requires little or no hacking. Form elements are particularly problematic since elements such as checkboxes and select menus render entirely different across browsers. There are UI libraries to standardize them, although these use Javascript: https://jqueryui.com/ Alternatively, Bootstrap can show how form elements can be standardized for the best possible cross-browser support: http://getbootstrap.com. – Toby Jul 18 '16 at 17:55
  • The way how one impletements this might be a bad practice, but I think it's necessary that there should be a way to truly reset these elements. Or maybe I'm being picky, idk :) Oh, and I have no experience with Bootstap. Maybe someone can show how it implements this. – akinuri Jul 18 '16 at 18:12
  • Apologies - what I was specifically referring to was the idea that you can/should reset elements on a per-pixel level for every single browser. Consider on iOS for example, browsers show a completely different UI for select menus that you are not even able to control using CSS. Here is Bootstrap's (admittedly) hefty chunk of code relating to positioning in form elements: https://github.com/twbs/bootstrap/blob/master/dist/css/bootstrap.css#L2549-L2695. Bootstrap also uses many containing elements such as labels and divs to control position of form elements. – Toby Jul 18 '16 at 18:51
  • `appearance` is in [CSS UI 4](https://drafts.csswg.org/css-ui-4/#appearance-switching) draft. – Oriol Jul 18 '16 at 19:14
  • @Oriol I didn't know it was re-considered. I'm glad they did. Updated the question with the link you commented. – akinuri Jul 18 '16 at 19:37
  • @akinuri Updated my answer a little with an alternative to `apperence` – Asons Jul 18 '16 at 19:41
  • As `:before` and `:after` render inside a container, it is not suppose to work in single tag elements like `input`, though in this case Chrome renders it anyway. Src: http://www.w3.org/TR/CSS2/generate.html#before-after-content – Asons Jul 18 '16 at 20:06
  • 1
    Hm...I disagree that drop-shadow counts as part of an element's size. Actual `drop-shadow` is a CSS attribute that doesn't directly affect an element's size, so I'm working off of that ideology. – Katana314 Jul 18 '16 at 20:31
  • @Katana314 I don't mean the `box-shadow` property. I was referring to general drop-shadow effect which seems to be applied to the checkbox element. It might be a shadow, or border. Doesn't really matter. Element's physical size is 13x13. Its visual size is 12x12 plus 1px for the shadow. – akinuri Jul 18 '16 at 20:47
  • Why do you want your own CSS reset? There are already CSS resets, normalize.css is probably the best one. ( https://necolas.github.io/normalize.css/ ) – Aloso Jul 18 '16 at 22:39

1 Answers1

1

May I suggest you go another way, a basic styling and then let the browsers have their way of render its controls.

Src: Styling HTML forms

Here is good form reset CSS, adjust it to your requirements

Src: https://gist.github.com/anthonyshort/552543

/* ----------------------------------------------------------------------------------------------------
Super Form Reset
A couple of things to watch out for:
- IE8: If a text input doesn't have padding on all sides or none the text won't be centered.
- The default border sizes on text inputs in all UAs seem to be slightly different. You're better off using custom borders.
- You NEED to set the font-size and family on all form elements
- Search inputs need to have their appearance reset and the box-sizing set to content-box to match other UAs
- You can style the upload button in webkit using ::-webkit-file-upload-button
- ::-webkit-file-upload-button selectors can't be used in the same selector as normal ones. FF and IE freak out.
- IE: You don't need to fake inline-block with labels and form controls in IE. They function as inline-block.
- By turning off ::-webkit-search-decoration, it removes the extra whitespace on the left on search inputs
----------------------------------------------------------------------------------------------------*/

input,
label,
select,
button,
textarea
{
 margin:0;
 border:0;
 padding:0;
 display:inline-block;
 vertical-align:middle;
 white-space:normal;
 background:none;
 line-height:1;
 
 /* Browsers have different default form fonts */
 font-size:13px;
 font-family:Arial;
}

/* Remove the stupid outer glow in Webkit */
input:focus
{
 outline:0;
}

/* Box Sizing Reset
-----------------------------------------------*/

/* All of our custom controls should be what we expect them to be */
input,
textarea
{
 -webkit-box-sizing:content-box;
 -moz-box-sizing:content-box;
 box-sizing:content-box;
}

/* These elements are usually rendered a certain way by the browser */
button,
input[type=reset],
input[type=button],
input[type=submit],
input[type=checkbox],
input[type=radio],
select
{
 -webkit-box-sizing:border-box;
 -moz-box-sizing:border-box;
 box-sizing:border-box;
}

/* Text Inputs
-----------------------------------------------*/

input[type=date],
input[type=datetime],
input[type=datetime-local],
input[type=email],
input[type=month],
input[type=number],
input[type=password],
input[type=range],
input[type=search],
input[type=tel],
input[type=text],
input[type=time],
input[type=url],
input[type=week]
{
}

/* Button Controls
-----------------------------------------------*/

input[type=checkbox],
input[type=radio]
{
 width:13px;
 height:13px;
}

/* File Uploads
-----------------------------------------------*/

input[type=file]
{

}

/* Search Input
-----------------------------------------------*/

/* Make webkit render the search input like a normal text field */
input[type=search]
{
 -webkit-appearance:textfield;
 -webkit-box-sizing:content-box;
}

/* Turn off the recent search for webkit. It adds about 15px padding on the left */
::-webkit-search-decoration
{
 display:none;
}

/* Buttons
-----------------------------------------------*/

button,
input[type="reset"],
input[type="button"],
input[type="submit"]
{
 /* Fix IE7 display bug */
 overflow:visible;
 width:auto;
}

/* IE8 and FF freak out if this rule is within another selector */
::-webkit-file-upload-button
{ 
 padding:0;
 border:0;
 background:none;
}

/* Textarea
-----------------------------------------------*/

textarea 
{
 /* Move the label to the top */
 vertical-align:top;
 
 /* Turn off scroll bars in IE unless needed */
 overflow:auto;
}

/* Selects
-----------------------------------------------*/

select
{

}

select[multiple] 
{
 /* Move the label to the top */
 vertical-align:top;
}

Update based on question edit

Use a label + pseudo instead of appearance

* {
  margin: 0;
  padding: 0;
  border: 0;
  font: inherit;
  font-size: 100%;
  line-height: 1.2;
  vertical-align: baseline;
}
*,
*:before,
*:after {
  box-sizing: inherit;
}
body {
  margin: 10px;
  font-family: sans-serif;
  box-sizing: border-box;
}
input[type="radio"],
input[type="checkbox"] {
  display: none;
}
input[type="checkbox"] + label {
  position: relative;
  display: inline-block;
  width: 16px;
  height: 16px;
  border: 1px solid black;
  text-align: center;
}
input[type="checkbox"]:checked + label:after {
  content: "✔";
  display: inline-block;
  vertical-align: top;
  height: inherit;
  font-size: 14px;
  font-weight: bold;
}

input[type="radio"] + label {
  position: relative;
  display: inline-block;
  width: 16px;
  height: 16px;
  border: 1px solid black;
  border-radius: 50%;
  text-align: center;
  position: relative;
}
input[type="radio"]:checked + label:after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  margin: -4px 0 0 -4px;   /* half the width/height to center */
  width: 8px;
  height: 8px;
  background: black;
  border-radius: 50%;
}
<p>
  <input id="chk1" type="checkbox" checked="checked" />
  <label for="chk1"></label> <span style="font-size: 2em;">Red</span>
</p>

<p>
  <input id="rad1" type="radio" name="rad" />
  <label for="rad1"></label> <span style="font-size: 2em;">Up</span>
  <br>
  <input id="rad2" type="radio" name="rad" checked="checked" />
  <label for="rad2"></label> <span style="font-size: 2em;">Down</span>
</p>

Side note:

:before and :after renders inside a container and is not suppose to work in single tag elements like input, though in this case Chrome renders it anyway.

Src: http://www.w3.org/TR/CSS2/generate.html#before-after-content

Asons
  • 84,923
  • 12
  • 110
  • 165
  • I appreciate the answer, but this seems more like a workaround. It overrides the initial function of the label element. If I want to have a label element, not to function as a checkbox but itself, this won't work. This might have use for specific form design but since I'm creating CSS to reset browser behaviour, this falls short. – akinuri Jul 18 '16 at 20:09
  • @akinuri Well, yes and no, it is a workaround until CSS 4 arrives, and you can still use the label and set border etc. on the pseudo ... so if you need a solution, this is one as of today ... and to reset browser behaviour, I gave a good solution already – Asons Jul 18 '16 at 20:19
  • About your last comment on the question regarding `::before` and `::after`, I checked the link you posted but couldn't find where it says they can't be used on self-closing tags. Well, it makes sense that they shouldn't be used with self-closing tags, realized that only after you mentioned it. I'm curious if this behaviour is documented. – akinuri Jul 18 '16 at 20:27
  • @akinuri Here is a post about it: http://stackoverflow.com/questions/2587669/can-i-use-the-after-pseudo-element-on-an-input-field – Asons Jul 18 '16 at 20:42