Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
134 views
in Technique[技术] by (71.8m points)

html - How to create a background over non-sibling DOM nodes?

So I have a web page nicely organized as such:

<html>
  <head>...</head>
  <body>
    <header>header</header>
    <main style="max-width: 80vw; margin: 0 auto;">
      <section>section 1</section>
      <section>section 2</section>
      <section>section 3</section>
      <section>section 4</section>
    </main>
    <footer>footer</footer>
  </body>
</html>

I would like to have a background with linear-gradient spanning the header and the first section.
It raises two issues:

  • how to create an element that spans non-sibling DOM nodes?
  • how to create an element that spans over the limited width of the first section?

Ideally I would like to keep my HTML organization, because it is semantic.

Edit infallible-silence-wcjkr

question from:https://stackoverflow.com/questions/65645672/how-to-create-a-background-over-non-sibling-dom-nodes

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

how to create an element that spans non-sibling DOM nodes?

You can't. Valid HTML requires a hierarchy with only one direct parent (in your hypothetical example the first section would have two: main and the new one with a gradient).

If you wish to achieve this effect you have several options:

Alter your hierarchy

You could flatten your hierarchy into

<div class="gradient-wrapper">
  <header>header</header>
  <section>section 1</section>
</div>
<section>section 2</section>
<section>section 3</section>
<section>section 4</section>

and impose the original style of main onto the sections using

section {
  max-width: 80vw;
  margin: 0 auto;
}

.gradient-wrapper {
  background: linear-gradient(...);
}

This is the easiest method as it is vertically responsive by design: the gradient will automatically stretch to encompass its children.

Edit zealous-sound-7jvy4

Constant height using CSS

If the height of, and distance to your first section are known and constant, you can deploy a CSS hack to make the background of your header stick out to exactly the height of your section (without changing the original hierarchy).

header {
  position: relative;
}

header::before {
  display: block;
  width: 100%;
  content: "";
  position: absolute;
  z-index: -1;

  --first-section-height: (1px + 30vh + 2px);
  height: calc(100% + var(--first-section-height));

  background: linear-gradient(...);
}

For clarity I have created the --first-section-height variable which represents the total height from the bottom of your header to the bottom of your section.

1px is the border-bottom of header,
30vh is the constant height of your section and
2px is its border-top and border-bottom.

Edit vibrant-liskov-uw2zh

Javascript

If you wish to keep your original hierarchy and need your section to be variable sized or spaced, you could resort to javascript to listen for changes in the window size and position a div at the combined bounding boxes of the two elements. A minimal working example of that behaviour:

window.addEventListener("load", updateGradientBox);
window.addEventListener("resize", updateGradientBox);
updateGradientBox();

function updateGradientBox() {
  let header = document.querySelector("header");
  let section = document.querySelector("main section:first-child");
  let gradient = document.querySelector("#gradient");
  if (header === null || section === null || gradient === null) return;

  let rects = [header, section].map((el) => el.getBoundingClientRect());
  let rect = getCombinedBoundingRect(rects);

  gradient.style.top = `${rect.top}px`;
  gradient.style.left = `${rect.left}px`;
  gradient.style.width = `${rect.width}px`;
  gradient.style.height = `${rect.height}px`;
}

function getCombinedBoundingRect(rects) {
  const r = {
    top: Math.min(...rects.map((r) => r.top)),
    left: Math.min(...rects.map((r) => r.left)),
    bottom: Math.max(...rects.map((r) => r.bottom)),
    right: Math.max(...rects.map((r) => r.right))
  };
  return {
    ...r,
    width: r.right - r.left,
    height: r.bottom - r.top
  };
}
#gradient {
  position: absolute;
  display: block;
  z-index: -1;
  background: linear-gradient(rgba(217, 217, 217, 1) 0%, rgba(85, 85, 85, 1) 100%);
}
<div id="gradient"></div>
<header>header</header>
<main>
  <section>section 1</section>
  <section>section 2</section>
  <section>section 3</section>
  <section>section 4</section>
</main>
<footer>footer</footer>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...