0

I have a tooltip implementation that uses some CSS variables to customize. I'm using CSS calc to calculate arrow position inside like below:

--size: 16px;
--border-size: 1px;
--arrow-position: calc((var(--size) / -2) - var(--border-size));

Result is be -8px with the values above and it works well. But if I want to have a borderless tooltip and set --border-size: 0 (without unit) this doesn't work. I made a demonstration below.

There are some ways that I know to set a unit for a value in CSS like calc(var(--border-size) * 1px) but this doesn't work as well once --border-size is a value with unit, because one side of the multiplication should be always unitless.

I also considered using new @property but couldn't manage with it as well.

I'm targeting to write a calculation that will cover border size both unitless and with a unit, without asking extra variable to set. Any idea how to do that?

div {
  --size: 16px;
  --border-size: 1px;
  --arrow-position: calc((var(--size) / -2) - var(--border-size));
  --bg-color: white;
  
  border: var(--border-size) solid black;
  padding: var(--size);
  background-color: var(--bg-color);
  
  position: absolute;
  top: 120px;
  left: 120px;
  width: 200px;
}

div::before {
  content: '';
  box-sizing: border-box;
  display: block;
  position: absolute;
  top: var(--arrow-position);
  
  width: var(--size);
  height: var(--size);
  transform: rotate(45deg);
  border: var(--border-size) solid black;
  background-color: var(--bg-color);
  border-bottom: none;
  border-right: none;
}

div.no-border {
  --border-size: 0;
  --bg-color: gray;
  
  top: 200px;
}

div.with-unit {
  --border-size: 0px;
  
  top: 280px;
}
<div>
Tooltip Content
</div>

<div class="no-border">
Tooltip Without Borders
</div>


<div class="no-border with-unit">
Tooltip Without Borders with Unit
</div>

EDIT: Code above is for demonstrating the issue in a simple way. The real use case is a web component. You can check it here: https://github.com/Trendyol/baklava/pull/483

EDIT: The difference in this question from Why doesn't css-calc() work when using 0 inside the equation? is I already know the reason why it doesn't work. Instead, I'm looking for workarounds for it.

Murat Çorlu
  • 8,207
  • 5
  • 53
  • 78
  • Why do you want to have it unitless, and not just write `0 px`? – Gykonik May 05 '23 at 07:41
  • you have a class no-border, why not just forget the calc for this one and write border:none – pier farrugia May 05 '23 at 07:55
  • @Gykonik Because it's generally defined as best practice to not use units for length with `0` value. https://stylelint.io/user-guide/rules/length-zero-no-unit/ And this will be surprising for the developer that `border-size` variable doesn't work with unitless 0 (as it works with regular border-size property. – Murat Çorlu May 05 '23 at 07:58
  • @pierfarrugia this is for demonstration purposes. the real use case is a web component. You can check it here https://github.com/Trendyol/baklava/pull/483 – Murat Çorlu May 05 '23 at 07:59
  • 1
    @MuratÇorlu I don't really agree with that one, as you're using custom properties. It is written: "The following pattern is **not** considered a problem: a { --x: 0px; }" - and that's what you're basically doing. – Gykonik May 05 '23 at 08:35
  • *Because it's generally defined as best practice to not use units for length with 0* --> this is completely wrong and I highly advice you stop reading such outdated article. read this: https://www.oddbird.net/2022/08/04/zero-units/ (written by an editor of the CSS Spec) – Temani Afif May 05 '23 at 09:24
  • Hi @TemaniAfif. That's a really nice article and completely addresses the issue I have here. Then can we say the best practice should be the other way around, like always having units? Because now I come up with the solution of configuring our linter according to this. – Murat Çorlu May 05 '23 at 09:57
  • *is I already know the reason why it doesn't work. Instead, I'm looking for workarounds for it.* --> there is no workarounds, you have to specify the unit and the correct unit as well because not all of them are the same (`0%` is different from `0px` in many cases) – Temani Afif May 05 '23 at 10:04

1 Answers1

0

In short, you can't use unitless values here, use 0px instead of 0

For lengths, you can't use 0 to mean 0px (or another length unit); instead, you must use the version with the unit: margin-top: calc(0px + 20px); is valid, while margin-top: calc(0 + 20px); is invalid.

However, if you want to use only unitless variables, you can use this by multiplying with 1px.

--border-size: 1;
--arrow-position: calc((var(--size) / -2) - (var(--border-size) * 1px));

References :

Madan Bhandari
  • 2,094
  • 2
  • 26
  • 46
  • Actually, there are some ways to add units to variables in CSS, but I couldn't manage to make it with them as well. I edited my question with that information. – Murat Çorlu May 05 '23 at 08:13
  • For multiplication, one should be unitless, but when you have with unit that becomes invalid as `10px * 10px` is invalid and similar in division. – Madan Bhandari May 05 '23 at 08:20