Category Archives: CSS

Resizing a component relative to it’s parent (position: fixed)

In the previous post I mentioned how we can fix a footer to the bottom of the viewport, but we have an issue where the width extends outside the width of the parent.

NOTE: This post discusses a partial solution to this issue. In that, if the browser window size changes this works, but if your viewport size changes, it doesn’t. So for example if you have a flyout Drawer component or the likes which takes up space on the page, then no window resize takes place, only a layout change takes place. If I resolve this I’ll update this post.

To solve this we’re going to create a ref on our parent div and monitor it’s size changes and then apply them to our footer.

So assuming we’re using material-ui’s createStyle, with the following CSS (or use plain CSS or your preferred CSS library)

footer: {
  position: "fixed",
  bottom: 0,
  marginBottom: "10px",
  textAlign: "left",
},

Here’s an abridged version of my code (using a React functional component)

const targetRef: any = useRef(null);
const [relativeWidth, setRelativeWidth] = useState(0);

useLayoutEffect(() => {
  function updateWidth() {
    if (targetRef != null && targetRef.current != null) {
      setRelativeWidth(targetRef.current.offsetWidth);
    }
  }

  window.addEventListener("resize", updateWidth);
  updateSize();
  return () => window.removeEventListener("resize", updateWidth);
}, []);

return (
  <div ref={targetRef}>
    {/* our other elements */}
    <div className={classes.footer}
      style={{ width: relativeWidth }}>
      {/* our footer elements */}
    </div>
  </div>
);

So what we’re doing is getting a ref to the parent div and storing the relativeWidth in the component’s state using useState (which we set up at the start of the function). Using useEffect, we create a listener to the window’s resize events and then update our state. Finally in the footer style we set the width explicitly using then relativeWidth that we stored.

Not only will this now display correctly relative to the parent div, but also resize relative to it as well.

These are early days for this code, but so far this looks to work a treat.

How to create a footer using CSS

To create a footer, a div that sits at the bottom of your viewport, using the position: “fixed” CSS.

For example here’s a snippet using material-ui’s createStyles function

footer: {
  position: "fixed",
  bottom: 0,
  marginBottom: "10px",
},

This will display the element it’s assigned to at the bottom of the screen using the fixed and bottom attributes, just to give it a bit of space we’ll using marginBottom so it floats above the bottom of the screen.

There’s a problem with the fixed position. It’s width is relative to the viewport, not relative to the parent.

This mean’s in a situation where you might have a user interface where the screen is divided into two columns and you want the fixed div in the right most column, you’ll find the width will extend outside if the view.

We’ll look at how to solve this, in the next post.

CSS calc, you little beauty

When you have something like a React/material-ui appbar and maybe toolbars these would usually by set to a pixel height which is great, until we want to then expand a component beneath them and have it fill the available space ?

CSS calc() is here to save the day.

Here’s an example style in material-ui style code. In this code our appbar and toolbar’s combined height is 123px and we want the next component to fill the “container”. The following therefore calculates the available space by subtracting 123px from whatever 100% is.

const styles = (_theme: Theme) => ({
  container: {
    width: '100%',
    height: 'calc(100% - 123px)'
  },
});

Obviously we need to wrap our parent component in the withStyles function, i.e.

export withStyles(styles)(MyComponent);

then in the render method

const { classes } = this.props as any;
// ...
<div className={classes.container}>
// component to fill this space
</div>

React and CSS

Standard approach to CSS

In a previous post we looked at an animated button and the issue(s) of having CSS in a separate .css file.

To recap, CSS can be implemented in a standalone .css file, for example AniButton.css might look like this (this is an abridged version of the CSS used in the previous post)

.button {
  background: #2B2D2F;
  height: 80px;
  width: 200px;
  text-align: center;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 0;
  right: 0;
  margin: 0 auto;
  cursor: pointer;
  border-radius: 4px;
}

This can then be imported into our React jsx/tsx file using

import "AniButton.css"

and everything works as per standard CSS. A couple of downsides to this are the CSS is in global namespace and also we’re using another language/DSL to define CSS whereas, it’d be nice if we could do all this in one language, i.e. in this case JavaScript/TypeScript.

Inline the style

From this global approach we can look towards inline of the CSS and also at the same time, removing the different language/DSL issue by declaring CSS in a JavaScript JSON style object, for example we remove the .CSS file and it’s import and then include the CSS style as an object, like this

const styles = {
  button: {
    background: "#2B2D2F",
    height: "80px",
    width: "200px",
    textAlign: "center",
    position: "absolute",
    top: "50%",
    transform: "translateY(-50%)",
    left: "0",
    right: "0",
    margin: "0 auto",
    cursor: "pointer",
    borderRadius: "4px"
  }
};

to apply this style we will need to add a style attribute to each of the elements we want a style applied to, for example

<div className="button" style={styles.button}>
</div>

One obvious downside of this inclusion of CSS along with our code is the separation of concerns might be seen as being lost, i.e. styling is now included along with the component code, however I tend to see React as lacking that separation of markup and code which you get with something like XAML/WPF, so I suppose it’s simply down to your interpretation of such things.

Styled components

Another solution which is a bit of a combination of CSS (syntax wise the names do not change to camelCase nor are values wrapped in quotes) and JavaScript is to use a library such as styled-components or emotion.

I’m going to look at Emotion’s implementation, so run the following

yarn add @emotion/styled @emotion/core

Now we can replace our button CSS and inline JavaScript CSS with style components, for example within your JSX/TSX file implement the following

import styled from '@emotion/styled'

const Button = styled.div`
  background: #2B2D2F;
  height: 80px;
  width: 200px;
  text-align: center;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 0;
  right: 0;
  margin: 0 auto;
  cursor: pointer;
  borderRadius: 4px;
`;

Now in usage our code looks like this

<Button className="button" onClick={this.handleOnClick}>
  <div className="text" style={styles.text} onClick={this.handleOnClick}>Submit</div>
</Button>

The C in CSS

CSS (Cascading style sheets) can appear in various ways. Inline, embedded, part of a style section and so on. The order in which they “cascade” – in other words the order in which the browser uses the styles is very specific.

The order is shown below.

Inline

The inline style takes precedence over all other style mechanisms. An inline style is simply a style applied to an elements style attribute, for example

<p style="color:red">A red paragraph</p>

Embedded

If no inline style is found for an element then the browser looks for an embedded style. We embed a style within style element, as below

<head>
   <style>
      p { color:red }
   </style>
</head>

External

After the embedded style the browser looks for any external styles found via the link element.

<head>
   <link rel="stylesheet" type="text/css" href="theme.css">
</head>

Theme.css

p { color:red }

User

If none of the previous mechanisms yields a matching style the browser checks the user styles. These are styles defined for a specific user on their machine. Each browser has it’s own way of allowing a user to define their “user” styles. In Google Chrome there’s a file in the user profile, for example C:\Documents and Settings\\Local Settings\Application Data\Google\Chrome\User Data\Default\User StyleSheets\Custom.css

Browser

Finally if no match is found for any of the above, the browser uses it’s default settings for the style.

!Important

Along with the above the user can mark a style as important

<style>
   p { color:red !important}
</style>

In such situations where a property is marked with !important the browser will now give preference to these important properties. In essence the order of precedence of the !important properties are reversed, therefore user style sheet has higher !important precedence than an author supplied !important value.

Note: The Inline, embedded and separate stylesheet are collectively known as the author style sheets.