A "todo" app built to practice Object Oriented JavaScript
First, your markup. From first look, it looks like a loose set of elements. I cannot tell which parts are which immediately. One method you can use is BEM. It's primarily a CSS naming convention, but can easily be used to identify which elements belong to a group.

&lt;div class="todo"&gt;
  &lt;h1 class="todo__header&gt;TODO List&lt;/h1&gt;
  &lt;a class="todo__undo" href="#"&gt;UNDO&lt;/a&gt;
  &lt;ul class="todo__list"&gt;
    &lt;li class="todo__list-item"&gt;something&lt;/li&gt;
  &lt;/ul&gt;
  &lt;form class="todo__form&gt;
    &lt;input class="todo__input" type="text" placeholder="Enter your tasks here..."&gt;
    &lt;input class="todo__submit" type="submit" value="add"&gt;
  &lt;/form&gt;
&lt;/div&gt;


In this case, you have a todo block. Inside this todo block you have todo__element. If these elements have alternate states or styles from their default, you have todo__element--alternate. Simple naming convention.

This leads us to the next issue, CSS. First, the way you write CSS is very generic. You're styling using element selectors. This is fine if the app is isolated, but if you do this inside a bigger app, you risk affecting other elements not related to the todo list. 

.todo{...}
.todo__header{...}
.todo__undo{...}
/* and so on */


In this case, in conjunction with the BEM naming convention, you can easily target elements with class names. They all have the same specificity since they're all classes, and you can easily identify which groups of styles belong together and which groups of elements they affect.

Before we head over to JS, I notice that you have &lt;a id="undo" href="javascript:;"&gt;UNDO&lt;/a&gt;. Instead of putting a blank inline script on href, I suggest you put # and use event.preventDefault() in the click handler to prevent it from navigating. This is so that all your JS live in JS, not mixed anywhere.

Now in JS, I notice that you don't keep track of state in the script. You submit a todo, directly append to the DOM, and that's it. JS knows nothing about the todo items afterwards and state is held in the DOM. This works in small scale, but this becomes tricky when the app scales, when you do more data manipulation like item counts, multiple undos and that sort of stuff.

Following MVC and similar variations, data should live in the data layer, or just some sort of storage like a variable. View is the UI, a visual representation of the data in the model. Controller accepts interaction, usually the place where handlers and logic are written. You don't need overly complex code, but it's nice to have them clearly separated.

(function(){

  var todoList   = document.querySelector('.todo__list');
  var todoSubmit = document.querySelector('.todo__submit');
  var todoInput  = document.querySelector('.todo__input');
  var todoUndo   = document.querySelector('.todo__undo');

  // Our "model", which is just some data storage 
  var todos = [];

  // Our "controller", where all the logic goes
  function createTodo(item){
    // Return a todo object
  }

  function removeTodo(index){
    // Remove todo from todos at index
  }

  function addTodo(todo){
    // Add todo to todos
  }

  function renderTodos(){
    // For each item in todos, render an &lt;li&gt;
    // Add or remove from the DOM accordingly.
  }

  todoSubmit.addEventListener('click', function(){
    // get input value
    // createTodo
    // addTodo
    // clear input
    // renderTodos
  });

  todoUndo.addEventListener('click', function(){
    // get last todo
    // removeTodo
    // renderTodos
  });

}());


In the really abstract sample above, you can see that todos is the source of truth, the "model". renderTodos simply renders that array. That plus your initial DOM constitutes your "view", the UI. The controller is the logic, from the handlers to the utility functions. The only time the JS has to know about the DOM is in renderTodos. Everything else is just JS, arrays and objects. You can easily determine the number of items by getting the array length and adjust your render function accordingly.

Now you may wonder, the delete button is dynamically generated with the todo, but how would you bind if renderTodo should only construct DOM? How would the controller bind to it? That's where event delegation comes in. Events "bubble" up the DOM. Click a descendant element, the ancestors also count as clicked. We can attach an event on a parent item to listen for future elements.

// Attach event handler to todoList (the ul)
todoList.addEventListener('click', function(event){
  // check if event.target is the delete button from an li
});