Janneman Malan scored his third ODI century and anchored a strong South African batting effort, made more impressive in the absence of Quinton de Kock and Temba Bavuma.
Proteas 283 meant Sri Lanka will be required to pull off the third-highest successful chase under lights on the island - that too in 47 overs - to win the series with a game to spare.
Malan, playing in just his ninth ODI, now boasts an average of 104.50. He shared two half-century partnerships, 96 for the second wicket with Reeza Hendricks and 86 for the fourth wicket with Heinrich Klaasen, and battled cramp in an industrious innings with few boundaries. On a large and slow outfield, Malan ran 65 singles, four twos and two threes, with nine fours and one six in the 135 balls he faced.
Sri Lanka will be disappointed with their effort in the field, which was largely non-threatening even when they were able to keep South Africa quiet, and especially towards the end of the innings, where there were several misfields. Dushmantha Chameera and Dasun Shanaka conceded at seven runs an over or more, while Akila Dananjaya and Wanindu Hasaranga gave away more than six runs an over. The more economical bowlers, Praveen Jayawickrama, Chamika Karunaratne and Dhananjaya de Silva, all had overs in hand.
Malan and Aiden Markram started solidly and put on an opening stand of 43 in 8.5 overs, before Markram was lured into a drive off Karunaratne and edged to wicketkeeper Minod Bhanuka. That brought Hendricks, installed at No. 3 in place of the injured Bavuma, to the crease and he showed early aggression. Hendricks pulled the fourth ball he faced through midwicket for four, but Karunaratne and Hasaranga ensured it would be five more overs before Proteas breached the boundary again.
When opportunities came, Hendricks took on the role of the aggressor and was particularly strong against the short ball. Malan was more watchful but took his chances to accelerate when they came. He reached his fifty off 64 balls with a powerful sweep off Jayawickrama in the 23rd over. Four overs later, Hendricks reached his third ODI half-century with a single off the same bowler.
Their partnership was approaching a century when Hendricks played de Silva down the wrong line and was bowled, to force Proteas into another rebuilding phase. Rassie van der Dussen brought out his characteristic sweeps and reverse sweeps, survived a run-out chance on 11 and was dismissed when he dragged his back foot out of the crease, missed a sweep and was stumped.
Proteas were 177 for 3 after 36 overs, eyeing a score of 270-plus and Heinrich Klaasen intended to get them there. He reverse swept the second ball he faced for four and raced to 31 off the first 16 balls he faced before being given out lbw when Hasaranga beat his inside edge and hit him on the back pad. Klaasen reviewed and replays showed he was hit just outside the line of off stump and he survived.
Malan received little of the strike in that time and moved from 83 off 107 balls when Klaasen arrived in the 36th over to 99 off 125 in the 43rd. He reached his century off 126 balls, with a single off Chameera. Malan's cramp worsened as the innings drew to a close, to the point where he could not run as much, and had to chase the boundaries. He was dropped on 107, when he slog-swept Hasaranga to long-on where he was put down by Charith Asalanka. Malan went on to clear long-on for his first six and then found four more thanks to a misfield near the rope.
Both Klaasen and Malan were dismissed off successive deliveries in the next over but the damage was done. Proteas scored 97 runs in the last 10 overs despite losing three wickets for six runs in eight balls.
With inputs from ESPN.
SRI LANKA: Avishka Fernando, Minod Bhanuka (wk), Bhanuka Rajapaksa, Dhananjaya de Silva, Charith Asalanka, Dasun Shanaka (capt), Wanindu Hasaranga, Chamika Karunaratne, Akila Dananjaya, Dushmantha Chameera, Praveen Jayawickrama.
SOUTH AFRICA: Janneman Malan, Reeza Hendricks, Aiden Markram, Rassie van der Dussen, Wiaan Mulder, Heinrich Klaasen (wk), Andile Phehlukwayo, George Linde, Keshav Maharaj (capt), Kagiso Rabada, Tabraiz Shamsi.