We've just released a new feature in the editor here on CodePen: drag-resizeable editors. We wanted you to be able to drag the editors manually to the size you want. On paper, that design decision might look incredibly simple:

resizeable mockup

In reality though, it's not so simple.

How do you communicate the draggability?

Dragging the editor seperators is something that you couldn't do before but you can do now. So how do we let people know that? Slack does a nice job of that. Here's what that could be like:

We don't actually do this, but it would be cool.

Unfortunately we don't yet have a tour system like that we can leverage. We want to though - maybe someday.

We lucked out here in that we already have something draggable in the editor that people are already used to, the preview/editor divide. So we made the between-editor resizers look like that existing resizer. Hopefully that makes it pretty obvious.

both resizers

The cursor goes a long way in communicating the functionality as well.

  .vertical-resizer {
  cursor: ew-resize;
  /* or cursor: col-resize; */
}
.horizontal-resizer {
  cursor: ns-resize;
  /* or cursor: row-resize */
}

What exactly happens when you resize an editor?

Let's say you grab the resizer in between the HTML and CSS and drag it to the right, toward the CSS. Does it:

  1. Squish the neighboring editor (CSS), leaving the right-most editor (JS) alone?
  2. Squish the right-most editor (JS), leaving the neighboring editor (CSS) alone?
  3. Squish both other editors equally?

take-away

We went with #3 because it seems a little more elegant. But that's not the whole story. What if someone has already explicitly resized the CSS area, then goes and moves that same resizer? In that case, the behavior changes slightly and tries to maintain the integrity of the CSS editor while resizing the HTML editor.

It's not perfect, because we have no way of knowing if someone was trying to resize the CSS editor specifically or the JS editor specifically, or both. That goes for either of the editors. Perhaps we could test which is bigger and keep the priority on that one, but it's tricky no matter what.

What happens when the window resizes?

This is another tough one. We considered calculating the percentages of each open editor and setting them with that percentage when the dragging stops. That way the ratio of editor sizes is maintained if the window is then resized. That makes sense if the window ends up getting bigger, but doesn't do a great job of maintaining the integrity of a manually resized editor when the window gets smaller (you might have made an editor the perfect size and don't want it messed with).

We decided to, under most circumstances, just give the right-most editor more (or less) space. The idea is that dragging to resize editors is pretty easy, so you can quickly reappropriate the new space.

Closing editors entirely

Another related feature to this is the ability to close the editors entirely. In the iteration beore this, you could collapse editors, but there would always be a sliver of them left taking up space. We did that because there always needs to be some way to re-open a closed editor. To solve that problem, and allow fully-turned-off editors (highly requested), we moved to a set of pillbox toggles in the footer area.

on off editors
We placed them next to the icons for changing the editor layout, as those have always been there and are highly related.

We also prevent you from turning off all the editors at once, because, weird. If you want a full page view of the Pen, there is Full Page View and Live View, and combining Live View and the Editor is sweet.

I haven't done this yet at the time of this writing, but I'm planning to put close icons in the title bar of each editor, which will turn off the editor and toggle the button in the footer, making that experience more obvious.

How do these choices persist?

When we first rolled out the different layouts for the editors (editors on left or right, rather than top), we made special URL's for them. You can force a Pen to open in that style by adding /left/, /right/, or /top/ to any Pen URL, like:

http://codepen.io/danbhala/pen/ChIEt/right/

That way you can share them that was in case the demo is more compelling in that aspect ratio. But, it's not a setting that is forcefully tied to any particular Pen. We figured that choice is more of a personal preference. That preference persists automatically for you. If you have switched to the "left" style editor, that will persist automatically until you change it again.

When we rolled out the expandable and collapsible editors, that was slightly differnet. We figured if you had, for example, the JS editor collapsed, it was very likely because you weren't using JavaScript in this Pen, or it was mostly irrelevant. We also figured you might want to share it that way. So, when you toggle editors on or off, that actually changes the URL. Like:

http://codepen.io/thebabydino/pen/ulsqJ?editors=110

1 for "on"; 0 for "off"

This is still how it works now with the full-turn-offable editors, as it's really the same thing happening. But now we also have the ability to manually resize those editors. For now, we've decided to not persist that. It's not shareable and doesn't maintain in a page refresh. Partly because it's pretty quick and easy to adjust again, and partly because it would be fairly complex to get right.

We might ultimately persist this too though, if we can get it right. In part because it will serve double-duty. Persisting is a slight niceity, but it will mean that we can also send that data over Professor Mode, so that students can watch you resizing your editors on their screen. We've already done a ton of work making sure pretty much every UI change syncs in Professor Mode that way, so this would just take it one step further.

What tech is involved?

The way the editors worked before this, is that they were all absolutely positioned. If they were all open, they were 33.33% wide (or high) and positioned at either 0, 33.33%, or 66.66% in the respective direction. When editors collapsed or expanded, the position and size changed (and was transitioned, to make the change visually clear).

When I first started working on this, I kept that system. I added two resizers. I absolutely positioned them in between the editors. I made them draggable (we're using jQuery UI draggable at the moment, but should probably switch to Draggabilly since it's much lighter, works with translate which is cool, and has touch support). I attached events to the start/stop/drag events to do a bunch of math and figure out what size and position everything should be at. It all worked, but it was a lot of code and it felt pretty spaghetti-like to me. Worse, the resizers were just kinda plopped on the edges of the editors, overlapping some fairly important UI (scroll bar and settings icons). I could have adjusted all the math to fit them in more elegantly, but that made things even more complicated. Worse still, when you dragged one resizer, the other just stayed put. I could have fixed that as well, adding even more complication. I was losing enthusiasm for this.

Then one morning I ripped it all out and made all the editors and resizers use flexbox instead.

  .top-boxes {
  display: flex;
  width: 100%;
}
.box {
  flex: 1;
  min-width: 125px;
}
.editor-resizer {
  width: 6px;
  cursor: col-resize;
  background: linear-gradient(
    to right, #505050, #383838
  );
  /* goes along for the flexbox ride, not affected by jQuery UI */
  left: 0 !important;
}

This simplified the JavaScript math tremendously. Basically like this:

  resizer.draggable({
  drag: function(e, ui) {
    htmlEditor.css("flex", "0 1 " + ui.offset.left + "px");
  }
});

As you resize, it just changes the flex-basis on the appropriate element, and everything else comes along for the ride, the other resizer included. Turning off editors happens with a class name change on the body, and CSS handles the rest:

  body.state-htmlOff-cssOn-jsOn {
  .box-html {
    width: 0;
    flex: 0.0001; /* collapse to nothing, transition friendly */
    overflow: hidden;
    min-width: 0;
    .code-wrap {
      opacity: 0;
    }
  }
  #editor-resizer-html {
    display: none;
  }
}

The simplicity meant we could get more complicated with the UX without feeling overwhelmed. I put in little things, like the transitions on the editors are stopped while dragging is happening, but present when editors are toggled on and off. Best of both worlds.

Flexbox does mean IE 10 and up support only though, which we're cool with. If it turns out to be problematic, we can always switch to a display: table situation, which we could probably make work with deeper support.

What about the vertical editor layouts?

Part of the beauty of using flexbox is that the directionality is almost an afterthought. We just change the parent flex container to:

  .top-boxes {
   display: flex;
   flex-direction: column;
}

And the layout turns sideways. Widths instead of heights. No big deal. And because we're changing the flex-basis to change sizes, even the JavaScript is largely the same. Just a few math tweaks because of the header being above the editors, it's not as simple as using the draggable elements offset alone.

What about adding more elements?

Let's say we added a fourth editor. This new system is entirely ready for that. Not saying we will, but we might. It's possible we add multiple editors of the same time, or a JavaScript console, or something like that. Very little needs to change, which is awesome.

What about power users?

What power users (a lot of the people that use CodePen) want is keyboard commands. Sadly keyboard commands are very complicated on the web, and especially so on CodePen. Keyboard commands might be handled by CodeMirror, Emmet, the browser, the OS, or even our own custom stuff. There is pretty much no open command, and not using a modifier key is largely out too because you are mostly in the editor where keys type characters, not do commands.

The most desireable commands for toggling editors is command (or control) 1-2-3. The best idea we have so far is a key command for turning key commands on/off. That way we can offer obtrusive key commands as an opt-in. This is definitely the hopefully-someday bucket.

Still some quirks

  • When you turn the JS editor totally off, there is a little jerky motion that happens as it collapses. This is because the HTML and CSS editors need to go back to flex: 1 and redivide the space. If we don't do that, it's possible a turned-off editor might remain visible because it's been explicitly sized and there isn't enough to fill the space anymore. It's probably fixable, just need to figure it out, no need to hold up launch.
  • In either of the vertical layouts, the code fades out as you're resizing. That's not ideal because you might be resizing it based on code you see inside there. The reason it does that is because boxes that are 100% high inside a vertical flex child aren't 100% the height of that child, even if it has position: relative; - they are 100% as tall as the parent. Seems kinda like a bug to me, but maybe not. There is not explicit height on that child, the height is dependant on what is happening in flexbox land. To deal with that, we fade the code out, recalc the size when the dragging stops, and make the editor that new height, and fade it back in. Little weird but it works. If we didn't do that, code might awkwardly overlap other code as the editors are resized.

So yeah, kinda hard

There is a lot to consider on something like this! And I didn't even get into the actual coding of it. Or discuss the customer support part of it, when everybody tells us they hate it and wished we would change it back to the old way (until they get used to it =)).

final-thing


9,052 14 71