border-width in em - but set a minimum border-width
Asked Answered
D

2

8

I want a div to have a border-width relative to the font-size, so I set for example border-width: 0.1em;. But if the font size is too small, no border appears as it is rendered smaller as 0.5px. This is of course not what I want. Is there any chance to set a minimum border-width of 1px?

div {
    border: 0.1em solid black;
}
Dissolve answered 18/12, 2013 at 18:41 Comment(3)
No. Borders use pixels. You can use box-shadows to emulate borders and add em spaces on that.Footcloth
I don't see no reason why not to use relative length. Can you proof that? Percentage doesn't work though. Can you give me an example of the box-shadow solution? @Hiral I added the code I use, but it is obvious.Dissolve
You can also use thin, medium and thick for border-width (as long as they match your preferred width). They will scale with the interface.Duteous
P
5

In CSS3, you can try to (ab)use the max css function, if your browser supports it.

border-width: max(1px, 0.1em);
border-style: solid; 
border-color: black;

Unfortunately this awesome CSS3 feature isn't supported by any browsers yet, but I hope this will change soon!

But in CSS2 – no, you can't.
However, you can use JavaScript/jQuery to loop through all elements and increase the border size to 1px.

But this will eat so much performance your browser is gonna crash if you have too many elements on your page (e.g. a table with more than 50-100 rows).
So in other words, no it's not possible.

$("[id$='ReportViewerControl']").find('*')

    .each(function () {

        if($(this).is('#ParametersRowReportViewerControl *')) 
            return;

        //console.log("Processing an element");
        //var cls = $(this).attr("class");

        // Don't add a border to sort-arrow
        if ($(this).is('img')) {
            return;
        }

        var anywidth = $(this).css('width');
        var anywidth = parseFloat(anywidth);
        //console.log("anywidth: " + anywidth);


        //var lol = $(this).css('borderLeftWidth');
        var blw = $(this).css('border-left-width');
        var brw = $(this).css('border-right-width');
        var btw = $(this).css('border-top-width');
        var bbw = $(this).css('border-bottom-width');

        var borls = $(this).css('border-left-style') == "solid";
        var borrs = $(this).css('border-right-style') == "solid";
        var borts = $(this).css('border-top-style') == "solid";
        var borbs = $(this).css('border-bottom-style') == "solid";

        var blw = parseFloat(blw);
        var brw = parseFloat(brw);
        var btw = parseFloat(btw);
        var bbw = parseFloat(bbw);

        //parseInt($(this).css("borderRightWidth"))
        //console.log(parseInt($(this).css("borderLeftWidth")));

        // UpdateLock = true;


        // Set width to 1px where 0px
        if (anywidth == 0)
            $(this).css('width', '1px');

        if (borls && blw == 0.0 || (blw > 0.0 && blw < 1.0)) {
            //console.log("setting border width");
            $(this).css('border-left-width', '1px');
        }

        if (borrs && brw == 0.0 || (brw > 0.0 && brw < 1.0)) {
            $(this).css('border-right-width', '1px');
        }

        if (borts && btw == 0.0 || (btw > 0.0 && btw < 1.0)) {
            $(this).css('border-top-width', '1px');
        }

        if (borbs && bbw == 0.0 || (bbw > 0.0 && bbw < 1.0)) {
            $(this).css('border-bottom-width', '1px');
        }

        // UpdateLock = false;
    });           // End $('*').each
Proteiform answered 28/8, 2014 at 13:39 Comment(4)
Thanks, the min() function is exactly what I need, even though it is not supported yet.Dissolve
@luke: Carefull, difference between spoken language and math. You need the max function, not the min function ;) Between a border-width of 1px and 0.1em, for that the border is in minimum 1px (or larger) wide, you need to select the maximum of the two values !Proteiform
Seems like the min/max functions are not documented very well: This is where I read more about them but their example is wrong. Thanks! btw why do you write abuse? What is the function actually meant for?Dissolve
Remark: when you use sass the max() approach does not work, b/c sass overwrites native css functions. Does somebody know a solution to this problem?Mittel
K
2

It looks like different browsers handle borders thinner than 1px differently. In Firefox such borders appear to render as 1px wide, but in Chrome they go away. On the other hand it appears that Chrome renders box-shadow even if it's less than 1px, so using it instead of border might be a good idea (Christina was actually suggesting it in the comment to the question). Than again some browsers won't render box-shadow if it's too thin (Firefox does that). Additionally box-shadow does not add the the box model, so using extra margin might be necessary.

Here is an attempt at overcoming those problems. Note that I had to resort to JavaScript userAgent detection hack (just add one extra class to body if it's a webkit browser), because I wasn't able to achieve it using CSS alone.

if (navigator.userAgent.toLowerCase().indexOf("webkit") > -1)
{
    document.body.className += " webkitHack";
}
/* Borders */

.border{
  border:0.0625em solid black;
}

.shadowyBorder{
  box-shadow: 0 0 0 0.0625em black;
  /* Compensating for the fact that box-shadow doesn't count towards box model */
  margin: 0.0625em;
}

.comboBorder
{
  /* If it's not webkit use border */
  border:0.0625em solid black;
}

/* If it's webkit use box-shadow */
.webkitHack .comboBorder
{
  border: none;
  box-shadow: 0 0 0 0.0625em black;
  /* Compensating for the fact that box-shadow doesn't count towards box model */
  margin: 0.0625em;
}

/* Extras */
td, th
{
  padding:5px;
}
.em05
{
  font-size:8px;
}

.em1
{
  font-size:16px;
}

.em2
{
  font-size:32px;
}

.box
{
  display:inline-block;
  height:1em;
  width:1em;
}
<table>
  <tr>
    <th>Font size</th><th>Border</th><th>Box shadow</th><th>Box shadow in webkit</th>
  </tr>
  <tr>
    <td>
      8px
    </td>
    <td class="em05">
      <div class="box border"></div>
    </td>
    <td class="em05">
      <div class="box shadowyBorder"></div>
    </td>
    <td class="em05">
      <div class="box comboBorder"></div>
    </td>
  </tr>
  <tr>
    <td>
      16px
    </td>
    <td class="em1">
      <div class="box border"></div>
    </td>
    <td class="em1">
      <div class="box shadowyBorder"></div>
    </td>
    <td class="em1">
      <div class="box comboBorder"></div>
    </td>
  </tr>
  <tr>
    <td>
      32px
    </td>
    <td class="em2">
      <div class="box border"></div>
    </td>
    <td class="em2">
      <div class="box shadowyBorder"></div>
    </td>
    <td class="em2">
      <div class="box comboBorder"></div>
    </td>
  </tr>
</table>
Kalvin answered 17/4, 2015 at 21:22 Comment(2)
Using this method one can recreate border from all sides or just a single one, but to achieve a combinations of border on 2 or 3 sides using inset box-shadow with additional padding might be required.Kalvin
It appears current version of Chrome does render border thinner than 1px as 1px, however this trick might still be useful if one is targeting an older webkit browser (like Android Browser on Android 4.x etc.).Kalvin

© 2022 - 2024 — McMap. All rights reserved.