<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://www.lhsazevedo.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.lhsazevedo.dev/" rel="alternate" type="text/html" /><updated>2025-03-26T21:32:36+00:00</updated><id>https://www.lhsazevedo.dev/feed.xml</id><title type="html">Lucas Azevedo</title><subtitle>A blog about my tech tweakings</subtitle><entry xml:lang="en"><title type="html">Refreshing the PHP.net navbar and search</title><link href="https://www.lhsazevedo.dev/refreshing-the-php-navbar-design/" rel="alternate" type="text/html" title="Refreshing the PHP.net navbar and search" /><published>2024-11-10T23:45:00+00:00</published><updated>2024-11-10T23:45:00+00:00</updated><id>https://www.lhsazevedo.dev/refreshing-the-php-navbar-design</id><content type="html" xml:base="https://www.lhsazevedo.dev/refreshing-the-php-navbar-design/"><![CDATA[<h2 id="the-need-for-a-refresh">The need for a refresh</h2>
<p>If you haven’t visited <a href="https://www.php.net">PHP.net</a> in a while, you might have
missed some recent facelifts. The most notable update was the new <a href="https://www.php.net/releases/8.3">release
page</a> for PHP 8, launched in November 2020.
This refresh not only modernized the brand look but also did an excellent job at
showcasing what’s new in PHP. Following that, other two pages also got some
attention: the <a href="https://github.com/php/web-php/pull/459">new home hero section</a>
and the <a href="https://github.com/php/web-php/pull/684">thanks page</a>.</p>

<p>With those improvements, some other areas that had not yet been refreshed
started to feel a bit off, and one of them was the navigation bar and its search
UI:</p>

<figure class="bigger-image">
    <a target="_blank" href="/assets/images/2024-11-07-refreshing-the-php-navbar-design/previous.png">
        <img alt="Previous PHP.net navbar screenshot" src="/assets/images/2024-11-07-refreshing-the-php-navbar-design/previous.png" />
    </a>
    <figcaption class="caption">Previous PHP.net navbar</figcaption>
</figure>

<p>The previous navbar had three main issues:</p>
<ol>
  <li><strong>Contrast</strong>: The light blue background made the white text hard to read,
possibly explaining the choice of the back PHP logo.</li>
  <li><strong>Search UX</strong>: Search results were displayed in a scrollable dropdown divided
into 5 categories, each one with its own scroll, creating a nested scrolling
experience that made it challenging for users to navigate and find the
desired result, particularly on mobile.</li>
  <li><strong>Missing pages</strong>: A significant number of manual page, especially from the
Language Reference section, were not being correctly indexed. For example,
searching for “types” would not list the <a href="https://www.php.net/manual/en/language.types.php">Language Reference &gt;
Types</a> page. This is
critical for new users that are still learning the language basics or are not
familiar with the documentation structure.</li>
</ol>

<h2 id="an-incremental-approach">An incremental approach</h2>
<p>Back in 2022, discussions began within the community about what a potential
PHP.net redesign. <a href="https://github.com/php/web-php/pull/602#issuecomment-1207166889">A new
design</a> was
proposed, sparkling interesting ideas and feedback from members. However, due to
the large scope of the proposal and conflicting schedules of the team members,
the discussion didn’t progress much further.</p>

<p>During the process of decision-making in groups, reaching consensus gets harder
and harder as the scope and number of people involved increases. An alternative
approach for these cases is to focus on smaller incremental changes, and follow
a consent over consensus method for decision-making<sup id="fnref:con1" role="doc-noteref"><a href="#fn:con1" class="footnote" rel="footnote">1</a></sup><sup id="fnref:con2" role="doc-noteref"><a href="#fn:con2" class="footnote" rel="footnote">2</a></sup>.</p>

<p>Following this principle, I figured it would be a better idea to start with a
smaller component. I choose one from <a href="https://github.com/php/web-php/pull/602#issuecomment-1207166889">my
iteration</a> in
the full redesign proposal that seemed to be well received by the community: the
navigation bar.</p>

<figure class="bigger-image">
    <a target="_blank" href="/assets/images/2024-11-07-refreshing-the-php-navbar-design/new.png">
        <img alt="New navbar design" src="/assets/images/2024-11-07-refreshing-the-php-navbar-design/new.png" />
    </a>
    <figcaption class="caption">
        New navbar design  (click to open full size)
    </figcaption>
</figure>

<p>It became clear early on that redesigning the navbar without addressing the
search would create a mixed experience that would be perceived as worse than the
previous version. For this, I took inspiration from Algolia’s DocSearch UI,
widely used in documentation sites nowadays. Here’s the result:</p>

<figure class="bigger-image">
    <a target="_blank" href="/assets/images/2024-11-07-refreshing-the-php-navbar-design/new-search.png">
        <img alt="New search dialog" src="/assets/images/2024-11-07-refreshing-the-php-navbar-design/new-search.png" />
    </a>
    <figcaption class="caption">
        New search dialog design
    </figcaption>
</figure>

<h2 id="paying-off-technical-debt">Paying off technical debt</h2>
<p>The PHP.net front-end codebase has accumulated some technical debt over the
years. The stylesheets are based on Bootstrap 2 and it’s float based responsive
grid system (remember the <code class="language-plaintext highlighter-rouge">.clearfix</code> era?), and make heavy use of nested rules
that complicates maintenance and reusability. On the JavaScript side, the
previous search UI was a custom JQuery plugin that used Twitter’s
<a href="https://twitter.github.io/typeahead.js/">typeahead.js</a> for autocomplete and
<a href="https://twitter.github.io/hogan.js/">Hogan.js</a> for templating — both of which
are no longer maintained.</p>

<p>This presented an ideal opportunity to remove these dependencies from the
navbar, making it more maintainable and future-proof. The markup was rewritten
from scratch using the Bootstrap 5 offcanvas navigation component as a base
reference. The styles now use current CSS features such as flexbox and
variables, and follows the Block Element Modifier (BEM) methodology adopted in
previous contributions to avoid specificity issues and naming conflicts.</p>

<p>The existing search was implemented client-side using a JSON index of the manual
pages. While this may not be the best approach for a large site like PHP.net,
replacing it with a server-side implementation was beyond this proposal’s scope.
Instead, I focused on removing the JQuery dependency and fixing the most
critical issues<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup><sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup> it had, which resulted in significant short-term
improvements with relatively minimal effort. The new UI was implemented using
vanilla JavaScript with accessibility and progressive enhancement in mind, as
we’ll see in the next sections.</p>

<h2 id="progressive-enhancement">Progressive enhancement</h2>
<p>This was an interesting requirement that I hadn’t anticipated: both the mobile
navigation and the search should work even if JS is disabled or fails to load.
Admittedly, this wasn’t something I considered before, and while one may think
that this is a rare scenario, it’s actually not. JavaScript, unlike HTML, is not
fault-tolerant, and errors or network issues can critical features that rely
exclusively on it.</p>

<p>Surprisingly, many major programming language sites require JavaScript for
essential functions like mobile navigation and search. As of this writing, sites
such as <a href="https://kotlinlang.org/docs/home.html">Kotlin</a>,
<a href="https://doc.rust-lang.org/book/">Rust</a>,
<a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/">Swift</a>,
<a href="developer.mozilla.org">MDN</a> and <a href="https://dart.dev/">Dart</a> all require JS for
one or both of these functions. This dependency is also common in most Algolia’s
DocSearch powered documentation and sites using the MkDocs default theme.</p>

<p>A simple solution to this problem is to use progressive enhancement. This
strategy recommends fault tolerant web technologies like HTML and CSS to provide
a baseline implementation, and only then use JavaScript to enhance the
experience. This approach ensures accessibility across devices and network
conditions, while still offering a more interactive and dynamic experience when
possible. The <a href="https://gov.uk/">GOV.UK</a> website is an excellent example of this
practice and served as reference for our implementation.</p>

<h2 id="accessibility">Accessibility</h2>
<p>Accessibility was another area I’ve been wanting to get more involved with, and
this contribution was really a great opportunity to do so. Implementing the ARIA
roles and attributes correctly, ensuring focus indication and management, and
making the new features keyboard accessible were definitely fun tasks. Recently,
I had the chance to experiment Playwright for testing, and it was reassuring to
find that the codebase already had some visual regression tests in place. So new
end-to-end tests were added using Playwright’s emphasis on semantic HTML to
ensure the new UI remains accessible.</p>

<h2 id="conclusion">Conclusion</h2>
<p>Redesigning and implementing the PHP.net navbar and search UI was both an
interesting and rewarding experience. With the valuable review and feedback from
the active maintainers I was able to polish the design, improve the user
experience, address technical debt and enhance accessibility, while still
keeping it familiar to visitors.</p>

<p>I’m happy to share that the PR I proposed and implemented was accepted, and the
new navbar is now live on <a href="https://www.php.net">PHP.net</a>. But there are still a
lot to be improved, particularly in the documentation section. So, if you are
looking for a way to contribute to open source and/or improve your design and
development skills, this is a great opportunity. Keep your scope focused,
discuss your ideas with the community before starting, and be open to feedback
but focus your efforts on integrating the objections.</p>

<h2 id="notes">Notes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:con1" role="doc-endnote">
      <p><a href="https://www.hoop.app/blog/choose-consent-over-consensus-for-better-decision-making">Choose Consent Over Consensus For Better Decision Making</a> <a href="#fnref:con1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:con2" role="doc-endnote">
      <p><a href="https://www.sociocracyforall.org/consent-decision-making/">Consent decision making</a> <a href="#fnref:con2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p><a href="https://github.com/php/phd/pull/154">PR: Improve search index generation for PHP.net</a> <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p><a href="https://github.com/php/phd/pull/160">PR: Fix search index for pages without parent book</a> <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>lhs_azevedo</name></author><category term="blog" /><category term="open source" /><category term="ui/ux" /><category term="accessibility" /><category term="progressive enhancement" /><summary type="html"><![CDATA[The process of designing and implementing the new PHP.net navbar and search UI.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.lhsazevedo.dev/assets/images/php-navbar.png" /><media:content medium="image" url="https://www.lhsazevedo.dev/assets/images/php-navbar.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>