Encryption and decryption using alphabetic shifts
Part 1, Caesar cipher

Instead of printing one character at a time (inefficient), create a string using the str.join method.

''.join(chr(ord(char) + 5) for char in text)


The variable name i is associated with integer indexes and is misleading to use for a character.

Separate the encryption/decryption into a function

Rather than forcing printing text to screen, a function returning a string can be used in any other context as well. It also lets us use the similarity between encryption and decryption to reduce repetition in the code.

def caesar_shift(text, places=5):
    text = text.lower().replace(' ', '')
    return ''.join(chr(ord(char) + places) for char in text)


The number of places to shift is a parameter instead of hardcoded, with a default of 5 to work the same as your example when the argument is omitted. A value of -5 then decrypts the resulting string.

Handle out-of-range characters

The technique appears to be meant to only work on (English) letters. To avoid unintended results on different inputs, one option is to leave other characters unmodified.

Also, "wrap around" instead of substituting for characters outside of the alphabet, by using the modulus operator %.

from string import ascii_lowercase

def caesar_shift(text, places=5):
    def substitute(char):
        if char in ascii_lowercase:
            char_num = ord(char) - 97
            char = chr((char_num + places) % 26 + 97)
        return char
    text = text.lower().replace(' ', '')
    return ''.join(substitute(char) for char in text)


With the character substitution logic now being too long to fit comfortably in one line, I chose to separate it into a nested function.

Part 2, Vigenère cipher

Loop variables

Your loop here is somewhat confusing, in that the actual loop variable i goes unused while an additional variable j is used as the index. It could be written as follows to avoid that particular issue (using min in case the lengths are different).

for i in range(min(len(text), len(key))):
    print(chr(ord(text[i]) + ord(key[i]) - 96))


An even better, more idiomatic way to loop over multiple sequences (strings, lists etc.) is with the built-in zip function, which creates a tuple of elements for every loop iteration.

for text_char, key_char in zip(text, key):
    print(chr(ord(text_char) + ord(key_char) - 96))


Write as a function

Let's also apply the advice from the previous part and write it as a function.

def vigenere(text, key):
    return ''.join(caesar_shift(tc, ord(kc)-96) for tc, kc in zip(text, key))


Notice how it can be implemented using the caesar_shift function from above.

Handle different text and key lengths

What if the text to be encrypted or decrypted and the key are of different lengths? The convention is to repeat the key phrase.

While it wouldn't be too hard to write code for this from the beginning, it's often a good idea to look for something useful in the standard library. In this case, the itertools.cycle function turns out to be convenient.

from itertools import cycle

def vigenere(text, key):
    key = cycle(key)
    return ''.join(caesar_shift(tc, ord(kc)-96) for tc, kc in zip(text, key))


I've left out the input and output parts from this answer.