diff --git a/content/blog/css-stacking-context/index.md b/content/blog/css-stacking-context/index.md
index 54f78fab..be9a6eb9 100644
--- a/content/blog/css-stacking-context/index.md
+++ b/content/blog/css-stacking-context/index.md
@@ -1,13 +1,12 @@
---
{
- title: "Portals",
+ title: "Why is z-index not working?! - Explaining CSS Stacking Context",
description: "",
published: '2023-01-01T22:12:03.284Z',
authors: ['crutchcorn'],
- tags: ['webdev'],
+ tags: ['webdev', 'css', 'html'],
attached: [],
- order: 15,
- series: "The Framework Field Guide"
+ license: 'cc-by-4'
}
---
@@ -15,7 +14,7 @@
While building sufficiently useful modals can be a challenging task, a rudimentary modal can be completed even without JavaScript.
-While we'll loop back to JavaScript (using React, Angular, and Vue) in a bit, let's use some CSS and HTML in order to build a basic modal:
+Let's use some CSS and HTML in order to build a basic modal:
```html
@@ -240,7 +239,7 @@ Notice how the purple box seemingly remains on "top" when we re-arrange the CSS
Well...
-### Re-arrange HTML Elements to Change the Stacking Order
+# Re-arrange HTML Elements to Change the Stacking Order
Let's take the HTML we had before, and re-arrange it a bit:
@@ -258,7 +257,7 @@ Now if we look at the box order, we'll see...
Now our boxes have reversed their height order! This is because one of the deciding factors of an element's `z` position is its relationship to other elements.
-### Positioned Elements Behave Differently Than Non-Positioned Elements
+# Positioned Elements Behave Differently Than Non-Positioned Elements
> This is where things get confusing. Take your time with this chapter, it's okay to have to re-read this section multiple times.
@@ -343,7 +342,7 @@ While our green button now smoothly moves left when you hover over it, there's a
This is because positioning an element introduces a "stacked context". This means that our `relative` positioned element takes priority in the `z` layer over non-positioned elements.
-### Understanding more rules of Stacked Contexts
+# Understanding more rules of Stacked Contexts
While `relative` positioning is one way that you can take priority in a stacked context, it's far from the only way to do so. Here's a list of CSS rules that will take priority in a stacked context, from the lowest priority to the highest priority:
@@ -401,7 +400,7 @@ You would see the following order of elements:
This is because the `lime` and `slate` take priority over `yellow` and `cyan` thanks to their `relative` positioning, but are still in HTML order within the same `z` level priority and within the same stacking context.
-### Creating Stacking Contexts
+# Creating Stacking Contexts
> "Welp, that's enough reading in the book today"
@@ -523,17 +522,17 @@ Then it will show "Absolute" above "Opacity", thanks to the order of the HTML se
If we remove the `opacity: 0.99` from the `"Opacity"` `div`, then `"Absolute`" will be on top.
-### Stacking Stacking Contexts
+# Stacking Stacking Contexts
While the previous sections have been head scratchers, let's dive into mind melting territory: You can contain stacking contexts within other stacking contexts. 🤯
+// TODO: Write
+# The Problem with Stacking Contexts
-### The Problem with Stacking Contexts
-
-
+// TODO: Explain that `z-index` cannot escape
@@ -545,368 +544,3 @@ While the previous sections have been head scratchers, let's dive into mind melt
> - [What No One Told You About Z-Index - Philip Walton](https://philipwalton.com/articles/what-no-one-told-you-about-z-index/)
> - [Appendix E. Elaborate description of Stacking Contexts - W3C](https://www.w3.org/TR/CSS2/zindex.html)
-# What is a JavaScript portals?
-
-> What does any of that CSS stuff have to do with my JavaScript?!
-
-First: Tone. Second: Everything.
-
-
-
-# Using Local Portals
-
-// TODO: Write this
-
-
-
-
-
-## React
-
-// TODO: Write this
-
-```jsx
-import React, { useMemo, useState } from 'react';
-import ReactDOM from 'react-dom';
-
-export default function App() {
- const [portalRef, setPortalRef] = useState(null);
-
- const portal = useMemo(() => {
- if (!portalRef) return null;
- return ReactDOM.createPortal(
Hello, world!
, portalRef);
- }, [portalRef]);
-
- return (
- <>
-
setPortalRef(el)}
- style={{ height: '100px', width: '100px', border: '2px solid black' }}
- >
-
-
- {portal}
- >
- );
-}
-```
-
-
-
-## Angular
-
-While the other frameworks have something akin to a portal system built into their frameworks' core, Angular does not. Instead, the Angular team maintains a library called "Angular CDK" in order to have shared UI code for utilities such as portals.
-
-To use the Angular CDK, you'll first need to install it into your project:
-
-```
-npm i @angular/cdk
-```
-
-From here, we can import components and utilities directly from the CDK.
-
-```typescript
-import { PortalModule } from '@angular/cdk/portal';
-import { DomPortal } from '@angular/cdk/portal';
-
-@Component({
- selector: 'my-app',
- template: `
-
-
-
-
Hello, world!
- `,
-})
-class AppComponent implements AfterViewInit {
- @ViewChild('portalContent') portalContent: ElementRef
;
-
- domPortal: DomPortal;
-
- ngAfterViewInit() {
- // This is to avoid an:
- // "Expression has changed after it was checked"
- // error when trying to set domPortal
- setTimeout(() => {
- this.domPortal = new DomPortal(this.portalContent);
- });
- }
-}
-
-@NgModule({
- declarations: [AppComponent],
- imports: [BrowserModule, PortalModule],
- providers: [],
- bootstrap: [AppComponent],
-})
-export class AppModule {}
-```
-
-### Rendering `ng-template`
-
-There might be a flash of the `div` on screen before our `ngAfterViewInit` occurs. As such, we may want to use an `ng-template`:
-
-// TODO: Write
-
-```typescript
-import { PortalModule, TemplatePortal } from '@angular/cdk/portal';
-
-@Component({
- selector: 'my-app',
- template: `
-
-
-
- Hello, this is a template portal
- `,
-})
-class AppComponent implements AfterViewInit {
- @ViewChild('portalContent') portalContent: TemplateRef;
-
- viewContainerRef = inject(ViewContainerRef);
- domPortal: TemplatePortal;
-
- ngAfterViewInit() {
- // This is to avoid an:
- // "Expression has changed after it was checked"
- // error when trying to set domPortal
- setTimeout(() => {
- this.domPortal = new TemplatePortal(
- this.portalContent,
- this.viewContainerRef
- );
- });
- }
-}
-```
-
-
-
-
-
-## Vue
-
-// TODO: Write this
-
-```vue
-
-
-
-
-
-
- Hello, world!
-
-
-```
-
-We need this `v-if` in order to ensure that `portalContainerEl` has already been rendered and is ready to project content.
-
-
-
-// TODO: Write this
-
-
-
-
-
-# Application-Wide Portals
-
-// TODO: Write this
-
-
-
-## React
-
-// TODO: Write this
-
-```jsx
-import React, { useState, createContext, useContext } from 'react';
-import ReactDOM from 'react-dom';
-
-// We start by creating a context name
-const PortalContext = React.createContext();
-
-function ChildComponent() {
- const portalRef = useContext(PortalContext);
- if (!portalRef) return null;
- return ReactDOM.createPortal(Hello, world!
, portalRef);
-}
-
-export default function App() {
- const [portalRef, setPortalRef] = useState(null);
-
- return (
-
- setPortalRef(el)}
- style={{ height: '100px', width: '100px', border: '2px solid black' }}
- >
-
-
-
-
- );
-}
-```
-
-
-
-## Angular
-
-We can use a basic service to share our instance of a `Portal` between multiple components, parent and child alike.
-
-```typescript
-import { Portal, PortalModule, TemplatePortal } from '@angular/cdk/portal';
-
-@Injectable({
- providedIn: 'root',
-})
-class PortalService {
- portal: Portal | null = null;
-}
-
-@Component({
- selector: 'modal',
- template: `
- Test
- `,
-})
-class ModalComponent implements OnDestroy {
- @ViewChild('portalContent') portalContent: TemplateRef;
-
- viewContainerRef = inject(ViewContainerRef);
- domPortal: TemplatePortal;
-
- portalService = inject(PortalService);
-
- ngAfterViewInit() {
- // This is to avoid an:
- // "Expression has changed after it was checked"
- // error when trying to set domPortal
- setTimeout(() => {
- this.portalService.portal = new TemplatePortal(
- this.portalContent,
- this.viewContainerRef
- );
- });
- }
-
- ngOnDestroy() {
- this.portalService = null;
- }
-}
-
-@Component({
- selector: 'my-app',
- template: `
-
-
-
-
- `,
-})
-class AppComponent {
- portalService = inject(PortalService);
-}
-```
-
-
-
-
-
-## Vue
-
-```
-
-
-
-
-
-
-
-```
-
-
-
-
-
-// TODO: Write this
-
-
-
-# HTML-Wide Portals
-
-// TODO: Write
-
-
-
-## React
-
-// TODO: Write
-
-Alternatively, `ReactDOM.createPortal` supports passing an arbitrary HTML DOM node, such as `html.body`:
-
-```jsx
-import React, { useMemo } from 'react';
-import ReactDOM from 'react-dom';
-
-function ChildComponent() {
- const bodyEl = useMemo(() => {
- return document.querySelector('body');
- }, []);
- return ReactDOM.createPortal(Hello, world!
, bodyEl);
-}
-
-export default function App() {
- return ;
-}
-```
-
-## Angular
-
-// TODO: Write
-
-Can't do this
-
-## Vue
-
-// TODO: Write
-
-```vue
-
-
-
-
- Hello, world!
-
-```
-
-```vue
-
-
-
-
-
-
-```
-
-
-
-