6

I have a few adjacent span tags that are styled to be display: inline-block; like so:

span.mark {
  background-color: yellow;
  display: inline-block;
  vertical-align: center;
  border-width: 1px;
  border-color: red;
  border-style: solid;
  border-radius: 3px;
}
<p>Some <span class="mark">standalone</span> test. Some <span class="mark">continuous </span><span class="mark">elements </span><span class="mark">that</span> should be formatted together.</p>

<p>Some <span class="mark">normal </span><b><span class="mark">and strong</span></b> text that should be formatted together.</p>

So currently these span tags all get their own little borders. However, I want them to look like there's just one border around them all together. So, technicall, the outer ones should have border-width-left: 1px; for the first one and border-width-right: 1px; for the last one and the ones in the middle should have border-width: 1px 0px;.

Is there a way to do this in CSS? Basically the rule should be: "If this is a span with a mark class and the elements before and after me are spans with a mark class then apply middle element styling. If this is a span with a mark class and the element before me is not a element with a mark style and the element after me is a span element with a mark style, apply left element styling. Etc..."

I know there is span.mark:before and span.mark:after, but I don't actually want to style the element before or after the current one. I want to style the current one best on what comes before and after it. Also, I need to check for the class of the :before and :after elements.

edit: Maybe my example was too simplistic. There will be more than one string of <span> tags in a given <p>. The whole :first-of-type :last-of-type is looking very promising, I didn't know about those. I'm afraid the solution will be more complicated though, if it works at all...

MadMonkey
  • 609
  • 1
  • 6
  • 13
  • span.comment or span.mark? – Salman A Jan 11 '18 at 12:26
  • span.mark - stupid copy and paste mistake – MadMonkey Jan 11 '18 at 12:29
  • 1
    There's no way to do *exactly* what you ask; at maximum, you could use `:first-child` and `:last-child` to differentiate the first one and the last one. – Haroldo_OK Jan 11 '18 at 12:31
  • The answer isn't actually correct, you can select adjacent elements by class / tag / id (or other typical CSS selector) by simply using a `+` between them...ie `span.mark + .mark { border-left: none; }`. This question has already been answered [here](https://stackoverflow.com/questions/1817792/is-there-a-previous-sibling-css-selector) as well. – Levidps Jan 11 '18 at 13:15
  • 2
    Take a look and give me your thoughts: https://jsfiddle.net/42x9ugbe/ – UncaughtTypeError Jan 11 '18 at 13:17
  • 1
    @UncaughtTypeError that's a pretty sweet solution! I'll have to play around with it some more but I like it. Very pragmatic and sidestepping many problems since it works on a visual basis and not a structural one. – MadMonkey Jan 11 '18 at 14:47
  • Great, I'll be anticipating any further feedback. I'm considering posting this solution as an official answer, as it may prove useful to other readers as well. – UncaughtTypeError Jan 11 '18 at 14:52
  • @UncaughtTypeError That solution is great. – sol Jan 11 '18 at 14:53

2 Answers2

3

With the support of pseudo-elements and a combination of absolute positioning and stacking context the intended behaviour can be achieved.

The snippet embedded below demonstrates how every preceding element's pseudo-element is stacked below the following element; conveying the impression of seamless continuity while still maintaining the visual impression of a full border for stand-alone elements.

Code Snippet Demonstration:

span.mark {
    background-color: yellow;
    display: inline-block;
    border-width: 1px;
    border-color: red;
    border-style: solid;
    padding: 0px 2px;
    border-right: 0px;
    border-left: 0px;
    position: relative;
}

span.mark:after,
span.mark:before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    z-index: -1;
    /* for border-radius */
    border-radius: 3px;
    background: yellow;
    width: 5px;
    border-top: 1px solid red;
    border-bottom: 1px solid red;
}

span.mark:after {
    border-right: 1px solid red;
    right: -2px;
}

span.mark:before {
    border-left: 1px solid red;
    left: -2px;
}
<p>Some <span class="mark">standalone</span> test. Some <span class="mark">continuous </span><span class="mark">elements </span><span class="mark">that</span> should be formatted together.</p>

<p>Some <span class="mark">normal </span><b><span class="mark">and strong</span></b> text that should be formatted together.</p>
UncaughtTypeError
  • 8,226
  • 4
  • 23
  • 38
-2

Yes, I would use the :first-child and :last-child pseudo-selector to style the first/last span differently to the rest. See https://jsfiddle.net/samando27/xydqpbx8/1/

Sam Anderson
  • 301
  • 2
  • 8
  • Sorry mate, your answer isn't actually correct, you can use `+` to select next sibling and `~` to sibling that comes further down the DOM (not specifically the next one). Here's another question/answer for further reference -> [here](https://stackoverflow.com/questions/1817792/is-there-a-previous-sibling-css-selector) – Levidps Jan 11 '18 at 13:17