Napoli, last season's runners-up, made a flying start when Lorenzo Insigne drilled in Dries Mertens' cross-field pass after a swift counter attack.
Belgium international Mertens also provided the second when his sliding pass was squeezed in by Jose Callejon from a tight angle.
Juraj Kucka slid under Pepe Reina to give Milan hope before the break, but they could not find a second-half equaliser as Napoli stretched their unbeaten run to a 14th game in all competitions.
Teenage Milan keeper Gianluigi Donnarumma came closest in injury-time, running forward for a free-kick and heading straight at opposite number Reina.
Both clubs harbour ambitions of finishing in the top three at the end of the season, ensuring Champions League qualification in the process.
Milan, who have not reached Europe's premier club competition since 2014, had lost just once in 11 matches going into the San Siro clash, only to leave themselves too much to do after a slow start.
They stay fifth in the Italian top-flight, one point above neighbours Inter, while third-placed Napoli are now level with Roma and a point adrift of leaders Juventus.
Juventus, who are bidding for a record sixth straight Scudetto, host fourth-placed Lazio in Turin on Sunday (11:30 GMT).
Match ends, Milan 1, Napoli 2.
Second Half ends, Milan 1, Napoli 2.
Attempt missed. Davide Calabria (Milan) right footed shot from outside the box is too high.
Attempt saved. Gianluigi Donnarumma (Milan) header from the centre of the box is saved in the centre of the goal. Assisted by Suso.
Suso (Milan) wins a free kick in the attacking half.
Foul by Amadou Diawara (Napoli).
Offside, Milan. Davide Calabria tries a through ball, but Gianluca Lapadula is caught offside.
Suso (Milan) wins a free kick in the defensive half.
Foul by Piotr Zielinski (Napoli).
Foul by Juraj Kucka (Milan).
Raúl Albiol (Napoli) wins a free kick in the defensive half.
Attempt missed. Gabriel Paletta (Milan) header from the centre of the box is too high. Assisted by Suso with a cross following a corner.
Corner,  Milan. Conceded by Marko Rog.
Attempt blocked. Andrea Bertolacci (Milan) left footed shot from outside the box is blocked. Assisted by Juraj Kucka.
Foul by M'Baye Niang (Milan).
Amadou Diawara (Napoli) wins a free kick in the defensive half.
Substitution, Milan. M'Baye Niang replaces Mario Pasalic.
Delay over. They are ready to continue.
Substitution, Napoli. Marko Rog replaces Allan because of an injury.
Delay in match Allan (Napoli) because of an injury.
Corner,  Napoli. Conceded by Gustavo Gómez.
José Callejón (Napoli) is shown the yellow card.
(Milan) wins a free kick in the defensive half.
José Callejón (Napoli).
Offside, Milan. Andrea Bertolacci tries a through ball, but Gianluca Lapadula is caught offside.
Juraj Kucka (Milan) wins a free kick on the right wing.
Foul by Ivan Strinic (Napoli).
Mario Pasalic (Milan) wins a free kick in the attacking half.
Foul by Piotr Zielinski (Napoli).
Foul by Gustavo Gómez (Milan).
Lorenzo Insigne (Napoli) wins a free kick on the left wing.
Foul by Mario Pasalic (Milan).
Elseid Hysaj (Napoli) wins a free kick in the defensive half.
Offside, Milan. Davide Calabria tries a through ball, but Giacomo Bonaventura is caught offside.
Substitution, Milan. Andrea Bertolacci replaces José Sosa.
Substitution, Napoli. Piotr Zielinski replaces Marek Hamsik.
Substitution, Milan. Gianluca Lapadula replaces Carlos Bacca.
Gustavo Gómez (Milan) wins a free kick in the defensive half.
Foul by Dries Mertens (Napoli).
Corner,  Milan. Conceded by Raúl Albiol.

This article was about:
Napoli strengthened their bid for a Serie A top-three finish as their splendid recent form continued with a win at fifth-placed AC Milan.