-4

I am trying to make an input with prefix & suffix elements :

  • Alone, the input is rounded
  • With a prefix (resp. suffix), the left (resp. right) side is rounded, but not the right (resp. left) side
  • With both prefix & suffix, the input isn't rounded at all (the buttons are rounded)

I have managed to handle the prefix element, but I can't seem to find a CSS selector to say "Round the right side of the input if a element follows the input", let it be on the input or on its container.

I would like to do it in HTML/CSS only (no JS). Any ideas ?

PS : I am not asking for a previous sibling selector. I am asking if there is a way to select the input that is followed by a suffix. That includes :

  • previous sibling selector (which doesn't exist)
  • element being followed by another one (which is the opposite, so probably doesn't exist either)
  • parent container having an input as the last child and nothing else
  • parent having N children (allowing me to know that if there's 3 children, then the input should be rounded)

:root {
  --radius: 5px;
}

div {
  height: 36px;
  margin: 12px;
}

* {
  box-sizing: border-box;
}

input {
  height: 100%;
  padding: 0;
  border-radius: var(--radius);
  border: 1px solid #ccc;
  padding: 0 6px;
}

button {
  height: 100%;
  background: teal;
  border: 0;
  color: white;
}

button[prefix] {
  border-radius: var(--radius) 0 0 var(--radius);
}

button[suffix] {
  border-radius: 0 var(--radius) var(--radius) 0;
}


div > button[prefix] + input {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

div > button[suffix] ~ input {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
<div>
  <input type="text" placeholder="Type here">
</div>

<div>
  <button prefix>P</button>
  <input type="text" placeholder="Type here">
  <button suffix>S</button>
</div>

<div>
  <input type="text" placeholder="Type here">
  <button suffix>S</button>
</div>


<div>
  <button prefix>P</button>
  <input type="text" placeholder="Type here">
</div>
  • 1
    How is this NOT a previous sibling question...that's exactly what you are asking for? – Paulie_D May 21 '19 at 11:17
  • As you already mentioned, there is no [previous sibling selector](https://stackoverflow.com/q/1817792/3233827). It would probably be simplest, if you just added a class to the parent, depending on the scenario (`with-suffix` and/or `with-prefix`). You simply cannot select an element by its followed element (only the other way around). – ssc-hrep3 May 21 '19 at 11:17
  • @Paulie_D because as said, I'm looking for inspiration in the other two cases (using the parent container), since I can't seem to find a solution. The previous sibling selector is one of many possible solutions, not the only one ! –  May 21 '19 at 11:18
  • @ssc-hrep3 I am using a JS framework and the input would be encapsulated into a parent container like ``. At the moment, I am able to round the input thanks to JS, but I fugred it would be doable in CSS only, without having to use other classes, simply selectors. –  May 21 '19 at 11:19
  • @Paulie_D That's bold to say. I take your feedback into consideration, but maybe someone else might have solved this issue already (for instance, using the container) and you're not aware of it ? –  May 21 '19 at 11:21
  • @trichetriche I would definitely use additional classes instead of doing styling with JavaScript. This should be possible even when used in a JS framework (maybe a wrapper might be necessary). You could also add classes directly to those elements. – ssc-hrep3 May 21 '19 at 11:21
  • we can do it *visually* if you want some hacks – Temani Afif May 21 '19 at 11:23
  • @ssc-hrep3 but it would force me to add a class for every suffix I want to append, which is not practical for reusability ... But it seems like the only solution at the moment. –  May 21 '19 at 11:23
  • @TemaniAfif definitely ! –  May 21 '19 at 11:24
  • Perhaps something with `:not()`... – Paulie_D May 21 '19 at 11:24
  • @Paulie_D isn't `:not` working only on pseudo selectors ? I didn't manage to make it work with classes or selectors –  May 21 '19 at 11:24
  • Why not just e.g. in Angular ``? – ssc-hrep3 May 21 '19 at 11:27
  • @Paulie_D it's indeed working, I have posted an answer with it working. Thank you ! If you want, feel free to make the same answer so that I can upvote it, since I managed it thanks to you. –  May 21 '19 at 11:29
  • @ssc-hrep3 because that implies the dev has to know that he needs to add a class to the input, depending on the suffix/prefix. At this point, he can simply create his own class and do it by himself, which is not very practical to use. Right now, I'm indeed using Angular, and using JS/TS to round the previous sibling of a suffix. –  May 21 '19 at 11:30

2 Answers2

1

If it's only about visual effect you can consider pseudo element to hide the rounded corners:

:root {
  --radius: 5px;
}

div {
  height: 36px;
  margin: 12px;
}

* {
  box-sizing: border-box;
}

input {
  height: 100%;
  padding: 0;
  border-radius: var(--radius);
  border: 1px solid #ccc;
  padding: 0 6px;
}

button {
  height: 100%;
  background: teal;
  border: 0;
  color: white;
}

button[prefix] {
  border-radius: var(--radius) 0 0 var(--radius);
}

button[suffix] {
  border-radius: 0 var(--radius) var(--radius) 0;
  position:relative;
}


div > button[prefix] + input {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

div > button[suffix]:before {
  content:"";
  position:absolute;
  right:calc(100% + 4px);
  top:0;
  bottom:0;
  width:calc(var(--radius) + 2px);
  background:#fff;
  border: 1px solid #ccc;
  border-left:0;
}
<div>
  <input type="text" placeholder="Type here">
</div>

<div>
  <button prefix>P</button>
  <input type="text" placeholder="Type here">
  <button suffix>S</button>
</div>

<div>
  <input type="text" placeholder="Type here">
  <button suffix>S</button>
</div>


<div>
  <button prefix>P</button>
  <input type="text" placeholder="Type here">
</div>

Another idea is to always have prefix/suffix element at the start and use order to visually change their place:

:root {
  --radius: 5px;
}

div {
  height: 36px;
  margin: 12px;
  display:flex;
}

* {
  box-sizing: border-box;
}

input {
  height: 100%;
  padding: 0;
  border-radius: var(--radius);
  border: 1px solid #ccc;
  padding: 0 6px;
  margin:0 5px;
}

button {
  height: 100%;
  background: teal;
  border: 0;
  color: white;
}

button[prefix] {
  border-radius: var(--radius) 0 0 var(--radius);
  order:-1;
}

button[suffix] {
  border-radius: 0 var(--radius) var(--radius) 0;
  order:1;
}


div > button[prefix] ~ input {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
div > button[suffix] ~ input {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
<div>
  <input type="text" placeholder="Type here">
</div>

<div>
  <button prefix>P</button>
  <button suffix>S</button>
  <input type="text" placeholder="Type here">
</div>

<div>
  <button suffix>S</button>
  <input type="text" placeholder="Type here">
</div>


<div>
  <button prefix>P</button>
  <input type="text" placeholder="Type here">
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • I like the second one ! For the first one, unfortunately it depends on the background, meaning I would have to use JS to get the parent color and make it dynamic (or have a weird coloring issue) –  May 21 '19 at 11:32
  • @trichetriche no need JS, you can still use CSS variable for background like you are doing for radius ;) – Temani Afif May 21 '19 at 11:33
  • That would be great, unfortunately I am creating Web components, so they should stand alone, and if variables are used, it means the user would have to style the pseudo elements themselves :/ –  May 21 '19 at 11:36
  • @trichetriche will edit with a transparent idea, hold on ;) – Temani Afif May 21 '19 at 11:36
  • @trichetriche well nevermind, you already found a good solution wilth not() selector, no need a more hacky way – Temani Afif May 21 '19 at 11:41
  • I wouldn't mind having th solution for a transparent background, as I don't know how to do that and it would certainly be useful for the future :D –  May 21 '19 at 11:49
  • @trichetriche ok, here is the idea: https://jsfiddle.net/es3b0tfx/2/ ... the trick is to build the corner using only pseudo element but there is a lot of code and a bit tricky to maintain – Temani Afif May 21 '19 at 12:10
  • Okay so it's not really a transparent background, but rather a standalone rounded corner, with the color being the color of the border. I like that, I've seen Material using it for their new inputs (outlined) ! –  May 21 '19 at 12:59
0

Answering to @Paulie_D, I realized I could indeed use :not with :last-child selector : if the input isn't the last child, then it's indeed followed by a suffix !

:root {
  --radius: 5px;
}

div {
  height: 36px;
  margin: 12px;
}

* {
  box-sizing: border-box;
}

input {
  height: 100%;
  padding: 0;
  border-radius: var(--radius);
  border: 1px solid #ccc;
  padding: 0 6px;
}

button {
  height: 100%;
  background: teal;
  border: 0;
  color: white;
}

button[prefix] {
  border-radius: var(--radius) 0 0 var(--radius);
}

button[suffix] {
  border-radius: 0 var(--radius) var(--radius) 0;
}


div > button[prefix] + input {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

input:not(:last-child) {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
<div>
  <input type="text" placeholder="Type here">
</div>

<div>
  <button prefix>P</button>
  <input type="text" placeholder="Type here">
  <button suffix>S</button>
</div>

<div>
  <input type="text" placeholder="Type here">
  <button suffix>S</button>
</div>


<div>
  <button prefix>P</button>
  <input type="text" placeholder="Type here">
</div>