Mirage Parties – A front-end case study

13 min read
Watb Team
An outdoor festival themed party

Turning this into reality however was the ultimate challenge. First of all, the home page design was split column with each section alternately slanted. Secondly, the home page would be image heavy, whilst also having a section that revealed a looping video on hover. Thirdly, the party planner request form would be not only in the format of natural language, but contained within a modal. Lastly, this all needed to not only work beautifully on desktop, but mobile too.

And that’s just the home page.

Let’s explore each feature.

Slanted layout

A slanted layout is not too difficult to achieve in itself. It can be done by wrapping each slanted element with a parent container, then applying the relevant slant to the parent, with a counter slant to the child element in the opposite direction.


<!-- HTML generated using hilite.me --><div style="background: #f8f8f8; overflow:auto;width:auto;padding:.8em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #0000FF; font-weight: bold">.parent</span> {
transform<span style="color: #666666">:</span>rotate(<span style="color: #666666">-5</span>deg);
<span style="color: #0000FF; font-weight: bold">.child</span> {
transform<span style="color: #666666">:</span>rotate(<span style="color: #666666">5</span>deg);

Nesting the child element with the parent will ensure that all content within the child element is straight – but the parent element itself is slanted. This means the edges of the container are at an angle, creating a cool effect with a background image. Depending on your background image, you may want to counter rotate that too the the subject matter is straight.

This effect can be achieved with CSS Shapes, but lack of support makes that unsuitable for now.

To complete your effect, you’ll need good old fashioned negative margins on each parent container. Without the negative margins, you’ll have gaps in between each.


Unavoidably, rendering of text suffers. It suffers even more if you are applying any further effects or animations either to the text itself or in front of the text or behind. Notably with Mirage, a canvas animation on the main section causes the text to blur slightly. This was a trade off that ultimately we accepted. I tried many different fixes but none were successful.

Video on hover

This was tricky as I’d never done this before. The idea was to have a section reveal a a video on hover, in place of the background but still behind the content, looping endlessly. Initially I tried to achieve this with YouTube as I wanted to keep heavy files off the site for better loading.

Unfortunately, with YouTube I could never get the video to play on hover quick enough, there was always an initial wait whilst the video loaded. Even preloading the video did not solve the problem. Therefore, I went native with HTML5 video.

The video itself is positioned outside of the flow of the content.

<!-- HTML generated using hilite.me --><div style="background: #f8f8f8; overflow:auto;width:auto;padding:.8em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #0000FF; font-weight: bold">.videowrap</span> {
 <span style="color: #008000; font-weight: bold">position</span><span style="color: #666666">:</span> <span style="color: #008000; font-weight: bold">absolute</span>;
 <span style="color: #008000; font-weight: bold">top</span><span style="color: #666666">:</span> <span style="color: #666666">-15%</span>;
 <span style="color: #008000; font-weight: bold">left</span><span style="color: #666666">:</span> <span style="color: #666666">0</span>;
 <span style="color: #008000; font-weight: bold">width</span><span style="color: #666666">:</span> <span style="color: #666666">110%</span>;
 <span style="color: #008000; font-weight: bold">height</span><span style="color: #666666">:</span> <span style="color: #666666">110%</span>;
 <span style="color: #008000; font-weight: bold">z-index</span><span style="color: #666666">:</span> <span style="color: #666666">98</span>;
 <span style="color: #008000; font-weight: bold">display</span><span style="color: #666666">:</span><span style="color: #008000; font-weight: bold">none</span>;

The odd positioning is due to the slanted container. Then with a bit of JS, we can trigger the video to play on hover:

<!-- HTML generated using hilite.me --><div style="background: #f8f8f8; overflow:auto;width:auto;padding:.8em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #008000; font-weight: bold">var</span> videoContainer <span style="color: #666666">=</span> $(<span style="color: #BA2121">&#39;.js-vid&#39;</span>);
<span style="color: #008000; font-weight: bold">var</span> video <span style="color: #666666">=</span> $(<span style="color: #BA2121">&#39;.bgvideo&#39;</span>);
videoContainer.hover(<span style="color: #008000; font-weight: bold">function</span>() {
   <span style="color: #008000; font-weight: bold">if</span> (video.hasClass(<span style="color: #BA2121">&#39;active&#39;</span>)) {
     video.removeClass(<span style="color: #BA2121">&#39;active&#39;</span>);
     video[<span style="color: #666666">0</span>].pause();
   } <span style="color: #008000; font-weight: bold">else</span> {
     video.addClass(<span style="color: #BA2121">&#39;active&#39;</span>);
     video[<span style="color: #666666">0</span>].play();

Natural Language Form Modal

This was one of the hardest elements of the site to pull off. A natural language form in itself is not so tricky to achieve, but fitting it within a modal that would work across devices added an extra dimension of difficulty. None of the examples I tried out previously made by other developers worked responsively either.

To get around the form working responsively, from tablet size downwards I made each popup field vertically and horizontally centered across the screen.

Responsive Form example

I also designed and then developed a unique animation for the modal, we wanted it to really catch the users attention when it came into view. To make it smoother, the content with the modal would gently animate downwards.

The end result was a form that from the users point of view is an experience in itself, emphasising the fact that the parties Mirage offer are like no other.

Animated Menu example

Snap SVG Animated Menu

The aim of the home page of the site is to act as a funnel, directing web visitors to the relevant part of the site, be they corporate or private clients. Mirage therefore wanted to avoid if possible having a main navigation bar on the site.

We advised them against this, but reached a compromise by having the menu revealed through a hamburger button, much like many sites already do on mobile. This is still quite a taboo thing to do, with many arguing this makes navigating the site too tricky. User familiarity with the hamburger is also hotly debated, but my point of view is simple. Whilst called a hamburger, the icon resembles a list which graphically is identical to how a vertical menu is laid out, giving the icon a good degree of affordance as to what it does.

Further, like many icons, the more it is used the more users will become familiar with it. The demographic of Mirage also suggested particularly tech savvy users, so ultimately we rolled with the idea.

Much like the modal, we wanted the menu to be different and to give off an air of razzmatazz. We achieved this by implementing SVG animation. This works by taking two SVG paths and animating the points between the two.

When doing so, it’s important that both SVG paths have the same points, and that you think very carefully about how the points will animate between the different paths.

The best idea is to achieve your second path by editing the first path in Illustrator or Inkscape. There is fantastic article by Codrops on off-canvas effects and we adapted their ideas onto Mirage.

Performance Considerations

Performance is key to everything we do at WATB and right from the very first step we are designing with speed and efficiency in mind.

With Mirage, this would be particularly challenging. The design is image heavy, and on the home page in particular with videos on hover and rotating background images also to factor in, achieving a high level of performance would be tricky.


Many front-end developers still don’t focus much on painting and fps. But in the era of CSS3 animations, canvas and SVG it’s imperative we consider how well our designs perform in-browser.

On the Mirage home page, we have canvas animation, CSS3 animations, transitions and SVG animations all to consider.

In Google Chrome developer tools a tool exists specifically for the purpose of measuring and optimising paint performance. Slow paint times and slow FPS will mean a juddery site that feels sluggish to use. Opening up dev tools and switching to the timeline tab, we can record a timeline of browser events whilst firing an animation. This gives us a screen like the one below.

Painting and Fps

The general target with any browser animation is not to go below 60fps. In the records pane is broken down each stage of rendering, and we can then see on the timeline how long each stage took the browser to complete.

One way to avoid a sluggish feel to the site is to utilise CSS3 transforms. Many developers still animate the position of an element by transitioning margins or using absolute positioning and then transitioning the top/left/right/bottom property. However, if you animate transforms instead, the browser will be able to utilise the GPU to assist in rendering.

Animating using transforms also does not trigger the browser to do a layout (calculating geometry) which is an expensive operation.

I’d recommend reading through this HTML5 Rocks article that further explains considerations of painting and fps. Ultimately 60fps is not always achievable, but as you can see in the screenshot which was a recording of FPS whilst triggering the modal, despite its fairly complex animation only momentarily does the FPS drop down to 30. Observed, it’s silky smooth unless you are on an older machine.

Page Speed

How do you get such a complex, image heavy site to load quickly? One of the best ways I find to achieve a fast page speed is to trim the fat. This is where using tools like Grunt and Bower correctly can have a positive impact. Using Grunt, we can concat and uglify our JS but importantly we can ensure we only include the files we actually need. I’ve encountered many developers that flesh out a project using Foundation, only end up using the modal JavaScript, but concat and uglify the entire foundation library into their project resulting in a 200-400kb file – 90% of which they’re not even using.

Unfortunately snap.svg is pretty hefty, even minified it’s still a 72kb file. This did add bulk to the build file but regardless, by keeping on top of what I was including in my build process I was able to keep the file size down. A secondary technique was to split off JS that was only being used on a particular page. For example, the animation for the canvas element on the home page is loaded separately on the home page only, meaning it is not loaded unnecessarily on other pages.

The same considerations apply to CSS, and the end result is that despite all the different elements, animations, videos and images the Mirage home page still loads in a respectful time frame.

Beyond the home page

There is of course a site beyond the home page, and when it came to building out these pages we were presented with fresh challenges. For example, on the parties page, three parties are displayed up the top of the page (each occupying its space in a different way) whilst at the bottom all the parties would be listed.

Anybody that has worked with WordPress and PHP knows that loops are the primary way it spits out the content it’s given. A loop works by only writing out the code (PHP and HTML) once, and then the loop will recycle that code and repeat it for each result. The difficulty you then have with such a complex layout is how you control laying out and styling parties differently. Ultimately, I achieved this by controlling the top three parties outside of the normal loop. This allowed me to style and lay them out as per the design. Control of the top three was built in using custom fields whereby the site admin can specify which parties to place up top, the code then fetches the relevant data.

A more interesting challenge though was handling how to display the services used for each party. The site admin needed to be able to specify which services were used for a party, and then the site retrieve the relevant data (a brief description and a link to a page with more information). Custom fields allowed me to add to the site a repeater field, which allows the site admin to control the information (service name, service description).

I had to figure out how to then pull these services onto the edit pages for each party, and then allow the site admin to choose which ones to display on the page. The code below is how to achieve this. You’ll also need to add the relevant custom field to the post edit screen.

<!-- HTML generated using hilite.me --><div style="background: #f8f8f8; overflow:auto;width:auto;padding:.8em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #008000; font-weight: bold">function</span> acf_services_populater( $field ) {
<span style="color: #408080; font-style: italic">// reset choices</span>
   $field[<span style="color: #BA2121">&#39;choices&#39;</span>] <span style="color: #666666">=</span> array();
<span style="color: #408080; font-style: italic">// if has rows</span>
<span style="color: #008000; font-weight: bold">if</span>( have_rows(<span style="color: #BA2121">&#39;services&#39;</span>, <span style="color: #BA2121">&#39;option&#39;</span>) ) {
<span style="color: #408080; font-style: italic">// while has rows</span>
       <span style="color: #008000; font-weight: bold">while</span>( have_rows(<span style="color: #BA2121">&#39;services&#39;</span>, <span style="color: #BA2121">&#39;option&#39;</span>) ) {
<span style="color: #408080; font-style: italic">// instantiate row</span>
<span style="color: #408080; font-style: italic">// vars</span>
           $value <span style="color: #666666">=</span> get_sub_field(<span style="color: #BA2121">&#39;service_name&#39;</span>);
           $label <span style="color: #666666">=</span> get_sub_field(<span style="color: #BA2121">&#39;service_name&#39;</span>);
<span style="color: #408080; font-style: italic">// append to choices</span>
           $field[<span style="color: #BA2121">&#39;choices&#39;</span>][ $value ] <span style="color: #666666">=</span> $label;            
<span style="color: #408080; font-style: italic">// return the field</span>
   <span style="color: #008000; font-weight: bold">return</span> $field;    
add_filter(<span style="color: #BA2121">&#39;acf/load_field/name=services_used&#39;</span>, <span style="color: #BA2121">&#39;acf_services_populater&#39;</span>);

You then need another bit of code in the template to loop through the options selected and retrieve the matching data from the site options.

<!-- HTML generated using hilite.me --><div style="background: #f8f8f8; overflow:auto;width:auto;padding:.8em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #666666">&lt;?</span>php
   $selectedService <span style="color: #666666">=</span> get_field(<span style="color: #BA2121">&#39;services_used&#39;</span>);
$allServices <span style="color: #666666">=</span> get_field(<span style="color: #BA2121">&#39;services&#39;</span>,<span style="color: #BA2121">&#39;options&#39;</span>);
echo <span style="color: #BA2121">&#39;&lt;ul class=&quot;ticklist&quot;&gt;&#39;</span>; foreach ($selectedService as $selService) {
     foreach ($allServices as $service) {
       <span style="color: #008000; font-weight: bold">if</span> ($service[<span style="color: #BA2121">&#39;service_name&#39;</span>] <span style="color: #666666">==</span> $selService) {
         echo <span style="color: #BA2121">&#39;&lt;li&gt;&lt;h3&gt;&#39;</span> . $service[<span style="color: #BA2121">&#39;service_name&#39;</span>] . <span style="color: #BA2121">&#39;&lt;/h3&gt;&#39;</span>;
         echo <span style="color: #BA2121">&#39;&lt;p&gt;&#39;</span> . $service[<span style="color: #BA2121">&#39;service_description&#39;</span>] . <span style="color: #BA2121">&#39;&lt;/p&gt;&#39;</span>;
         echo <span style="color: #BA2121">&#39;&lt;a href=&quot;&#39;</span> . $service[<span style="color: #BA2121">&#39;service_link&#39;</span>] . <span style="color: #BA2121">&#39;&quot;&gt;More info&lt;/a&gt;&lt;/li&gt;&#39;</span>;
 echo <span style="color: #BA2121">&#39;&lt;/ul&gt;&#39;</span>;
<span style="color: #666666">?&gt;</span>

Ultimately, what this allows the site admin to do is control the names of the services, the descriptions and links all from one place, but still have control over exactly which ones are displayed.

Moving on, there were also challenges with layouts that had to be overcome. For example, the site pulls in relevant parties through a loop on various pages (including through a shortcode). This in itself is not hard to achieve, but what becomes more difficult is how you control the layout when you have different numbers of posts all using the same loop. You can’t use a grid because if you use a four column layout but get five results, you’ll have a second row with only one result.

This was an excellent example of flexbox stepping up to the plate, as unlike a grid it can handle content responsively, so no matter whether you throw two posts or twenty-two posts at it, it will fill the rows. An example of this working can be seen below.

Mirage Parties Flexbox images

Closing thoughts

For someone still in the early throws of their career as a front-end developer, Mirage was a fantastic challenge for me where my skills were pushed to the limits. In pushing for our goal of achieving a beautiful, functional but very different from the rest result we had to overcome numerous technical difficulties. Ultimately though, in terms of translating the design into the browser I believe we were successful. Responsive, daring, elegant and engaging, Mirage is an awesome website that hopefully portrays as best as possible the attention to detail and high class of the parties and events themselves.

Visit the Site. The challenge we often face in this industry is to come up with a website that defies convention, whether it be in layout, function or style. With Mirage Parties our challenge was to defy all three. Collaborating closely with the design team, my job was to liaise with them throughout the concept phase, coming up with clever ideas to push the boundaries and give Mirage the site that adequately represented the incredible attention to detail that they themselves put into every party and event they do. This portrayal of high class and quality was imperative.Luckily, images was not a problem with Mirage, as they already had in their possession  a vast array of stunning photos that really drive home the ethos of these party planners. We therefore felt that focusing on imagery was the key, coupling the photos with classy typography and unobtrusive but elegant touches of style and animation.

The challenge we often face in this industry is to come up with a website that defies convention, whether it be in layout, function or style.

Related Posts

Posts you may also like