2

I'm using Prismjs alongside Mdx for a code-related blog. I'm using it to show code blocks in a manner consistent with other blogs.

I'm running into an issue where the rendered code blocks (inside a <pre> element are too wide on my mobile layout. For now I am content to have things scroll on the horizontal axis. I'm 99% certain that the <pre> elements are what's breaking the layout because when I comment them out of the blog post, the layout works as expected.

Specifically, I'm using a package called prism-react-renderer (alongside Gatsby), and the code I have for the CodeBlock element (that handles the syntax highlighting) is more or less verbatim from the documentation for prism-react-renderer, but is included here for convenience:

import React from 'react'
import Highlight, { defaultProps } from 'prism-react-renderer'
import theme from 'prism-react-renderer/themes/nightOwl'

const CodeBlock = (props) => {
  const className = props.children.props.className || ''
  const matches = className.match(/language-(?<lang>.*)/)
  return (
    <Highlight {...defaultProps} code={props.children.props.children.trim()} language={
      matches && matches.groups && matches.groups.lang
        ? matches.groups.lang
        : ''
    }
      theme={theme}>
      {({ className, style, tokens, getLineProps, getTokenProps }) => (
        <pre className={className} style={{ ...style }}>
          <code>
            {tokens.map((line, i) => (
              <div key={i} {...getLineProps({ line, key: i })}>
                {line.map((token, key) => (
                  <span key={key} {...getTokenProps({ token, key })} />
                ))}
              </div>
            ))}
          </code>
        </pre>
      )}
    </Highlight>
  )
}

export default CodeBlock

This is the component used in the blog post template that handles rendering the .mdx files into HTML:

import React from 'react'
import { Link, graphql } from 'gatsby'
import { MDXRenderer } from 'gatsby-plugin-mdx'
import { MDXProvider } from '@mdx-js/react'
import Layout from '../components/layout'
import CodeBlock from '../components/code-block'

const components = {
  pre: CodeBlock
}

const BlogPostTemplate = ({ data, pageContext, location }) => {
  const post = data.mdx
  const { previous, next } = pageContext

  return (
    <Layout>
      *** Removed irrelevant component ***
      <MDXProvider components={components}>
        <div className='blog-post-wrapper'>
          <article className='blog-post-content'>
            <header>
              <h1>
                {post.frontmatter.title}
              </h1>
              <time dateTime={post.frontmatter.date}>
                {post.frontmatter.date}
              </time>
            </header>
            <MDXRenderer>{post.body}</MDXRenderer>
          </article>
          <footer className='blog-post-footer'>
           *** Removed irrelevant components ***
          </footer>
        </div>
      </MDXProvider>
    </Layout>
  )
}

export default BlogPostTemplate

I have tried a few different things: flex shrink, applying overflow-x: scroll and overflow-x: auto to both the <pre> element and its parents. When I apply a fixed width to the <pre> element and overflow-x: scroll I can get the behavior I want but I'd like to not have to use a fixed width on this if possible. The .css I have looks like this, including some obviously ineffectual styles:

.blog-post-wrapper {
  display: flex;
  flex-direction: column;
  overflow-y: scroll;
  overflow-x: scroll;
}

.blog-post-content {
  flex-grow: 1;
  margin-bottom: 2rem;
  width: 100%;
  display: flex;
  flex-direction: column;
  overflow-y: scroll;
  overflow-x: scroll;
}

.blog-post-content .prism-code {
  padding: 20px;
  border: 3px solid red;
  flex-shrink: 1;
  overflow-y: scroll;
  overflow-x: scroll;
}

I'll attach images of the way the <pre> element is rendering presently, in inspector: Image of code block pushing outside of content area in mobile layout.

And this is how it looks if I set a fixed width (in inspector): Image of a fixed width code block, with expected overflow-x behavior - which is for content on the x-axis to scroll if it overflows.

Ferran Buireu
  • 28,630
  • 6
  • 39
  • 67
Anthony
  • 330
  • 3
  • 13

2 Answers2

2

Not ideal, but I found this combination of CSS properties working together:

pre code {
  display: inline-block;
  width: 80vw;
  overflow-x: auto;
}
Mikolasan
  • 626
  • 10
  • 19
1

It's probably too late, but I had the same issue and I was able to fix it by

  1. Adding max-width css property to the main layout. The value should be equal to window.screen.width. I had to use the following hack to be able to get the screen size:

    const [windowWidth, setWindowWidth] = useState(width)
    useEffect(() => {
        setWindowWidth(window.screen.width)
    }, [])
    
  2. Adding overflow: scroll to the pre in the CodeBlock

Savva
  • 21
  • 2